X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fnotification-thread-events.c;h=80ae8d00d1cf489f0605fe2e3ffb278e7d5c0dda;hp=4904a54575e512c1ed4297a98eed17e7abc95dea;hb=a57a7f22e21b8b5dbb32e6b0096c81e869543aa2;hpb=51eab943fe37b0fdd541099c4d02ea7b57cb15bb diff --git a/src/bin/lttng-sessiond/notification-thread-events.c b/src/bin/lttng-sessiond/notification-thread-events.c index 4904a5457..80ae8d00d 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.c +++ b/src/bin/lttng-sessiond/notification-thread-events.c @@ -209,7 +209,7 @@ struct channel_state_sample { }; static unsigned long hash_channel_key(struct channel_key *key); -static int evaluate_condition(const struct lttng_condition *condition, +static int evaluate_buffer_condition(const struct lttng_condition *condition, struct lttng_evaluation **evaluation, const struct notification_thread_state *state, const struct channel_state_sample *previous_sample, @@ -235,7 +235,8 @@ void session_info_put(struct session_info *session_info); static struct session_info *session_info_create(const char *name, uid_t uid, gid_t gid, - struct lttng_session_trigger_list *trigger_list); + struct lttng_session_trigger_list *trigger_list, + struct cds_lfht *sessions_ht); static void session_info_add_channel(struct session_info *session_info, struct channel_info *channel_info); @@ -339,24 +340,6 @@ int match_condition(struct cds_lfht_node *node, const void *key) return !!lttng_condition_is_equal(condition_key, condition); } -static -int match_client_list(struct cds_lfht_node *node, const void *key) -{ - struct lttng_trigger *trigger_key = (struct lttng_trigger *) key; - struct notification_client_list *client_list; - struct lttng_condition *condition; - struct lttng_condition *condition_key = lttng_trigger_get_condition( - trigger_key); - - assert(condition_key); - - client_list = caa_container_of(node, struct notification_client_list, - notification_trigger_ht_node); - condition = lttng_trigger_get_condition(client_list->trigger); - - return !!lttng_condition_is_equal(condition_key, condition); -} - static int match_client_list_condition(struct cds_lfht_node *node, const void *key) { @@ -515,6 +498,11 @@ void session_info_destroy(void *_data) } } lttng_session_trigger_list_destroy(session_info->trigger_list); + + rcu_read_lock(); + cds_lfht_del(session_info->sessions_ht, + &session_info->sessions_ht_node); + rcu_read_unlock(); free(session_info->name); free(session_info); } @@ -539,7 +527,8 @@ void session_info_put(struct session_info *session_info) static struct session_info *session_info_create(const char *name, uid_t uid, gid_t gid, - struct lttng_session_trigger_list *trigger_list) + struct lttng_session_trigger_list *trigger_list, + struct cds_lfht *sessions_ht) { struct session_info *session_info; @@ -565,6 +554,7 @@ struct session_info *session_info_create(const char *name, uid_t uid, gid_t gid, session_info->uid = uid; session_info->gid = gid; session_info->trigger_list = trigger_list; + session_info->sessions_ht = sessions_ht; end: return session_info; error: @@ -629,6 +619,27 @@ error: return NULL; } +/* RCU read lock must be held by the caller. */ +static +struct notification_client_list *get_client_list_from_condition( + struct notification_thread_state *state, + const struct lttng_condition *condition) +{ + struct cds_lfht_node *node; + struct cds_lfht_iter iter; + + cds_lfht_lookup(state->notification_trigger_clients_ht, + lttng_condition_hash(condition), + match_client_list_condition, + condition, + &iter); + node = cds_lfht_iter_get_node(&iter); + + return node ? caa_container_of(node, + struct notification_client_list, + notification_trigger_ht_node) : NULL; +} + /* This function must be called with the RCU read lock held. */ static int evaluate_condition_for_client(struct lttng_trigger *trigger, @@ -714,7 +725,7 @@ int evaluate_condition_for_client(struct lttng_trigger *trigger, goto end; } - ret = evaluate_condition(condition, &evaluation, state, + ret = evaluate_buffer_condition(condition, &evaluation, state, NULL, last_sample, 0, channel_info->session_info->consumed_data_size, channel_info); @@ -759,8 +770,6 @@ int notification_thread_client_subscribe(struct notification_client *client, enum lttng_notification_channel_status *_status) { int ret = 0; - struct cds_lfht_iter iter; - struct cds_lfht_node *node; struct notification_client_list *client_list; struct lttng_condition_list_element *condition_list_element = NULL; struct notification_client_list_element *client_list_element = NULL; @@ -799,13 +808,8 @@ int notification_thread_client_subscribe(struct notification_client *client, condition_list_element->condition = condition; cds_list_add(&condition_list_element->node, &client->condition_list); - cds_lfht_lookup(state->notification_trigger_clients_ht, - lttng_condition_hash(condition), - match_client_list_condition, - condition, - &iter); - node = cds_lfht_iter_get_node(&iter); - if (!node) { + client_list = get_client_list_from_condition(state, condition); + if (!client_list) { /* * No notification-emiting trigger registered with this * condition. We don't evaluate the condition right away @@ -815,8 +819,6 @@ int notification_thread_client_subscribe(struct notification_client *client, goto end_unlock; } - client_list = caa_container_of(node, struct notification_client_list, - notification_trigger_ht_node); /* * The condition to which the client just subscribed is evaluated * at this point so that conditions that are already TRUE result @@ -858,8 +860,6 @@ int notification_thread_client_unsubscribe( struct notification_thread_state *state, enum lttng_notification_channel_status *_status) { - struct cds_lfht_iter iter; - struct cds_lfht_node *node; struct notification_client_list *client_list; struct lttng_condition_list_element *condition_list_element, *condition_tmp; @@ -902,18 +902,11 @@ int notification_thread_client_unsubscribe( * matching the condition. */ rcu_read_lock(); - cds_lfht_lookup(state->notification_trigger_clients_ht, - lttng_condition_hash(condition), - match_client_list_condition, - condition, - &iter); - node = cds_lfht_iter_get_node(&iter); - if (!node) { + client_list = get_client_list_from_condition(state, condition); + if (!client_list) { goto end_unlock; } - client_list = caa_container_of(node, struct notification_client_list, - notification_trigger_ht_node); cds_list_for_each_entry_safe(client_list_element, client_tmp, &client_list->list, node) { if (client_list_element->client->socket != client->socket) { @@ -1132,6 +1125,39 @@ int match_session(struct cds_lfht_node *node, const void *key) return !strcmp(session_info->name, name); } +/* Must be called with RCU read lock held. */ +static +struct lttng_session_trigger_list *get_session_trigger_list( + struct notification_thread_state *state, + const char *session_name) +{ + struct lttng_session_trigger_list *list = NULL; + struct cds_lfht_node *node; + struct cds_lfht_iter iter; + + cds_lfht_lookup(state->session_triggers_ht, + hash_key_str(session_name, lttng_ht_seed), + match_session_trigger_list, + session_name, + &iter); + node = cds_lfht_iter_get_node(&iter); + if (!node) { + /* + * Not an error, the list of triggers applying to that session + * will be initialized when the session is created. + */ + DBG("[notification-thread] No trigger list found for session \"%s\" as it is not yet known to the notification system", + session_name); + goto end; + } + + list = caa_container_of(node, + struct lttng_session_trigger_list, + session_triggers_ht_node); +end: + return list; +} + /* * Allocate an empty lttng_session_trigger_list for the session named * 'session_name'. @@ -1316,7 +1342,8 @@ struct session_info *find_or_create_session_info( sessions_ht_node); assert(session->uid == uid); assert(session->gid == gid); - goto error; + session_info_get(session); + goto end; } trigger_list = lttng_session_trigger_list_build(state, name); @@ -1324,7 +1351,8 @@ struct session_info *find_or_create_session_info( goto error; } - session = session_info_create(name, uid, gid, trigger_list); + session = session_info_create(name, uid, gid, trigger_list, + state->sessions_ht); if (!session) { ERR("[notification-thread] Failed to allocation session info for session \"%s\" (uid = %i, gid = %i)", name, uid, gid); @@ -1334,6 +1362,7 @@ struct session_info *find_or_create_session_info( cds_lfht_add(state->sessions_ht, hash_key_str(name, lttng_ht_seed), &session->sessions_ht_node); +end: rcu_read_unlock(); return session; error: @@ -1425,6 +1454,7 @@ int handle_notification_thread_command_add_channel( hash_channel_key(&new_channel_info->key), &channel_trigger_list->channel_triggers_ht_node); rcu_read_unlock(); + session_info_put(session_info); *cmd_result = LTTNG_OK; return 0; error: @@ -1515,6 +1545,113 @@ end: return 0; } +static +int handle_notification_thread_command_session_rotation( + struct notification_thread_state *state, + enum notification_thread_command_type cmd_type, + const char *session_name, uid_t session_uid, gid_t session_gid, + uint64_t trace_archive_chunk_id, + struct lttng_trace_archive_location *location, + enum lttng_error_code *_cmd_result) +{ + int ret = 0; + enum lttng_error_code cmd_result = LTTNG_OK; + struct lttng_session_trigger_list *trigger_list; + struct lttng_trigger_list_element *trigger_list_element; + struct session_info *session_info; + + rcu_read_lock(); + + session_info = find_or_create_session_info(state, session_name, + session_uid, session_gid); + if (!session_info) { + /* Allocation error or an internal error occured. */ + ret = -1; + cmd_result = LTTNG_ERR_NOMEM; + goto end; + } + + session_info->rotation.ongoing = + cmd_type == NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING; + session_info->rotation.id = trace_archive_chunk_id; + trigger_list = get_session_trigger_list(state, session_name); + if (!trigger_list) { + DBG("[notification-thread] No triggers applying to session \"%s\" found", + session_name); + goto end; + } + + cds_list_for_each_entry(trigger_list_element, &trigger_list->list, + node) { + const struct lttng_condition *condition; + const struct lttng_action *action; + const struct lttng_trigger *trigger; + struct notification_client_list *client_list; + struct lttng_evaluation *evaluation = NULL; + enum lttng_condition_type condition_type; + + trigger = trigger_list_element->trigger; + condition = lttng_trigger_get_const_condition(trigger); + assert(condition); + condition_type = lttng_condition_get_type(condition); + + if (condition_type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING && + cmd_type != NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING) { + continue; + } else if (condition_type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED && + cmd_type != NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_COMPLETED) { + continue; + } + + action = lttng_trigger_get_const_action(trigger); + + /* Notify actions are the only type currently supported. */ + assert(lttng_action_get_type_const(action) == + LTTNG_ACTION_TYPE_NOTIFY); + + client_list = get_client_list_from_condition(state, condition); + assert(client_list); + + if (cds_list_empty(&client_list->list)) { + /* + * No clients interested in the evaluation's result, + * skip it. + */ + continue; + } + + if (cmd_type == NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING) { + evaluation = lttng_evaluation_session_rotation_ongoing_create( + trace_archive_chunk_id); + } else { + evaluation = lttng_evaluation_session_rotation_completed_create( + trace_archive_chunk_id, location); + } + + if (!evaluation) { + /* Internal error */ + ret = -1; + cmd_result = LTTNG_ERR_UNK; + goto end; + } + + /* Dispatch evaluation result to all clients. */ + ret = send_evaluation_to_clients(trigger_list_element->trigger, + evaluation, client_list, state, + session_info->uid, + session_info->gid); + lttng_evaluation_destroy(evaluation); + if (caa_unlikely(ret)) { + goto end; + } + } +end: + session_info_put(session_info); + *_cmd_result = cmd_result; + rcu_read_unlock(); + return ret; +} + static int condition_is_supported(struct lttng_condition *condition) { @@ -1560,8 +1697,6 @@ int bind_trigger_to_matching_session(const struct lttng_trigger *trigger, struct notification_thread_state *state) { int ret = 0; - struct cds_lfht_node *node; - struct cds_lfht_iter iter; const struct lttng_condition *condition; const char *session_name; struct lttng_session_trigger_list *trigger_list; @@ -1587,25 +1722,13 @@ int bind_trigger_to_matching_session(const struct lttng_trigger *trigger, goto end; } - cds_lfht_lookup(state->session_triggers_ht, - hash_key_str(session_name, lttng_ht_seed), - match_session_trigger_list, - session_name, - &iter); - node = cds_lfht_iter_get_node(&iter); - if (!node) { - /* - * Not an error, the list of triggers applying to that session - * will be initialized when the session is created. - */ + trigger_list = get_session_trigger_list(state, session_name); + if (!trigger_list) { DBG("[notification-thread] Unable to bind trigger applying to session \"%s\" as it is not yet known to the notification system", session_name); goto end; - } - trigger_list = caa_container_of(node, - struct lttng_session_trigger_list, - session_triggers_ht_node); + } DBG("[notification-thread] Newly registered trigger bound to session \"%s\"", session_name); @@ -1866,7 +1989,7 @@ int handle_notification_thread_command_unregister_trigger( enum lttng_error_code *_cmd_reply) { struct cds_lfht_iter iter; - struct cds_lfht_node *node, *triggers_ht_node; + struct cds_lfht_node *triggers_ht_node; struct lttng_channel_trigger_list *trigger_list; struct notification_client_list *client_list; struct notification_client_list_element *client_list_element, *tmp; @@ -1919,20 +2042,15 @@ int handle_notification_thread_command_unregister_trigger( * Remove and release the client list from * notification_trigger_clients_ht. */ - cds_lfht_lookup(state->notification_trigger_clients_ht, - lttng_condition_hash(condition), - match_client_list, - trigger, - &iter); - node = cds_lfht_iter_get_node(&iter); - assert(node); - client_list = caa_container_of(node, struct notification_client_list, - notification_trigger_ht_node); + client_list = get_client_list_from_condition(state, condition); + assert(client_list); + cds_list_for_each_entry_safe(client_list_element, tmp, &client_list->list, node) { free(client_list_element); } - cds_lfht_del(state->notification_trigger_clients_ht, node); + cds_lfht_del(state->notification_trigger_clients_ht, + &client_list->notification_trigger_ht_node); free(client_list); /* Remove trigger from triggers_ht. */ @@ -2006,6 +2124,21 @@ int handle_notification_thread_command( cmd->parameters.remove_channel.domain, &cmd->reply_code); break; + case NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING: + case NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_COMPLETED: + DBG("[notification-thread] Received session rotation %s command", + cmd->type == NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING ? + "ongoing" : "completed"); + ret = handle_notification_thread_command_session_rotation( + state, + cmd->type, + cmd->parameters.session_rotation.session_name, + cmd->parameters.session_rotation.uid, + cmd->parameters.session_rotation.gid, + cmd->parameters.session_rotation.trace_archive_chunk_id, + cmd->parameters.session_rotation.location, + &cmd->reply_code); + break; case NOTIFICATION_COMMAND_TYPE_QUIT: DBG("[notification-thread] Received quit command"); cmd->reply_code = LTTNG_OK; @@ -2680,7 +2813,7 @@ bool evaluate_session_consumed_size_condition( } static -int evaluate_condition(const struct lttng_condition *condition, +int evaluate_buffer_condition(const struct lttng_condition *condition, struct lttng_evaluation **evaluation, const struct notification_thread_state *state, const struct channel_state_sample *previous_sample, @@ -3026,17 +3159,8 @@ int handle_notification_thread_channel_sample( * Check if any client is subscribed to the result of this * evaluation. */ - cds_lfht_lookup(state->notification_trigger_clients_ht, - lttng_condition_hash(condition), - match_client_list, - trigger, - &iter); - node = cds_lfht_iter_get_node(&iter); - assert(node); - - client_list = caa_container_of(node, - struct notification_client_list, - notification_trigger_ht_node); + client_list = get_client_list_from_condition(state, condition); + assert(client_list); if (cds_list_empty(&client_list->list)) { /* * No clients interested in the evaluation's result, @@ -3045,7 +3169,7 @@ int handle_notification_thread_channel_sample( continue; } - ret = evaluate_condition(condition, &evaluation, state, + ret = evaluate_buffer_condition(condition, &evaluation, state, previous_sample_available ? &previous_sample : NULL, &latest_sample, previous_session_consumed_total,