2 * Copyright (C) 2023 Kienan Stewart <kstewart@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include "../utils.hpp"
9 #include "event_name.hpp"
11 #include <common/container-wrapper.hpp>
12 #include <common/macros.hpp>
13 #include <common/make-unique.hpp>
16 #include <babeltrace2/babeltrace.h>
22 #include <unordered_set>
24 class event_name_set_operations
{
26 static const char *get(const bt_value
*array
, std::size_t index
)
28 const auto *names_entry
=
29 bt_value_array_borrow_element_by_index_const(array
, index
);
31 if (bt_value_get_type(names_entry
) != BT_VALUE_TYPE_STRING
) {
32 throw std::runtime_error(
33 "All members of the 'names' parameter array must be strings");
36 return bt_value_string_get(names_entry
);
39 static std::size_t size(const bt_value
*array
)
41 return bt_value_array_get_length(array
);
46 : public lttng::utils::random_access_container_wrapper
<const bt_value
*,
48 event_name_set_operations
> {
50 friend event_name_set_operations
;
53 lttng::utils::random_access_container_wrapper
<const bt_value
*,
55 event_name_set_operations
>(nullptr)
59 event_name_set(event_name_set
&& original
) noexcept
:
60 lttng::utils::random_access_container_wrapper
<const bt_value
*,
62 event_name_set_operations
>(
67 explicit event_name_set(const bt_value
*names
) :
68 lttng::utils::random_access_container_wrapper
<const bt_value
*,
70 event_name_set_operations
>(names
)
72 if (bt_value_get_type(names
) != BT_VALUE_TYPE_ARRAY
) {
73 throw std::invalid_argument("'names' parameter must be an array");
78 class event_name_filter
{
80 event_name_filter(bt_self_component_port_input
*input_port_
,
81 const event_name_set
& name_set
) :
82 input_port
{ input_port_
}, _names
{ name_set
.begin(), name_set
.end() }
86 bool event_name_is_allowed(const char *event_name
) const noexcept
88 return _names
.find(event_name
) != _names
.end();
92 bt_self_component_port_input
*const input_port
;
95 const std::unordered_set
<std::string
> _names
;
98 struct event_name_iterator_data
{
99 event_name_iterator_data(lttng::bt2::message_iterator_ref iterator_
,
100 const class event_name_filter
& event_name_filter_
) :
101 upstream_iterator
{ std::move(iterator_
) }, event_name_filter
{ event_name_filter_
}
105 ~event_name_iterator_data() = default;
107 const lttng::bt2::message_iterator_ref upstream_iterator
;
108 const class event_name_filter
& event_name_filter
;
112 bool message_passes(const bt_message
*message
, const event_name_filter
& event_name_filter
)
114 if (bt_message_get_type(message
) != BT_MESSAGE_TYPE_EVENT
) {
118 const bt_event
*event
= bt_message_event_borrow_event_const(message
);
119 const bt_event_class
*event_class
= bt_event_borrow_class_const(event
);
120 const char *event_name
= bt_event_class_get_name(event_class
);
122 if (event_name
== nullptr) {
126 return event_name_filter
.event_name_is_allowed(event_name
);
130 bt_component_class_initialize_method_status
131 event_name_initialize(bt_self_component_filter
*self_comp
,
132 bt_self_component_filter_configuration
*,
133 const bt_value
*params
,
136 bt_self_component_port_input
*input_port
;
137 std::unique_ptr
<class event_name_filter
> event_name_filter
;
139 auto self
= bt_self_component_filter_as_self_component(self_comp
);
140 if (bt_self_component_filter_add_input_port(self_comp
, "in", nullptr, &input_port
) !=
141 BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
142 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self
,
143 "Failed to add input port");
144 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
147 if (bt_self_component_filter_add_output_port(self_comp
, "out", nullptr, nullptr) !=
148 BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
149 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self
,
150 "Failed to add output port");
151 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
154 const auto names_param
= bt_value_map_borrow_entry_value_const(params
, "names");
155 if (names_param
== nullptr) {
156 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
157 self
, "'names' parameter is required");
158 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
162 const event_name_set event_names
{ names_param
};
163 if (event_names
.empty()) {
164 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
165 bt_self_component_filter_as_self_component(self_comp
),
166 "'names' parameter must not be empty");
167 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
171 lttng::make_unique
<class event_name_filter
>(input_port
, event_names
);
172 } catch (const std::bad_alloc
&) {
173 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
174 self
, "Failed to allocate memory for private component data");
175 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
176 } catch (const std::exception
& ex
) {
177 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self
, "%s", ex
.what());
178 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
181 /* Ownership of event_name is transferred to the component. */
182 bt_self_component_set_data(self
, event_name_filter
.release());
183 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
;
186 void event_name_finalize(bt_self_component_filter
*self_comp
)
188 class event_name_filter
*event_name_filter
=
189 (class event_name_filter
*) bt_self_component_get_data(
190 bt_self_component_filter_as_self_component(self_comp
));
192 delete event_name_filter
;
195 bt_message_iterator_class_initialize_method_status
196 event_name_message_iterator_initialize(bt_self_message_iterator
*self_message_iterator
,
197 bt_self_message_iterator_configuration
*,
198 bt_self_component_port_output
*)
200 const auto& event_name_filter
=
201 *static_cast<class event_name_filter
*>(bt_self_component_get_data(
202 bt_self_message_iterator_borrow_component(self_message_iterator
)));
204 bt_message_iterator
*raw_iterator
;
205 if (bt_message_iterator_create_from_message_iterator(
206 self_message_iterator
, event_name_filter
.input_port
, &raw_iterator
) !=
207 BT_MESSAGE_ITERATOR_CREATE_FROM_MESSAGE_ITERATOR_STATUS_OK
) {
208 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
211 lttng::bt2::message_iterator_ref
iterator(raw_iterator
);
212 raw_iterator
= nullptr;
214 std::unique_ptr
<event_name_iterator_data
> iter_data
;
216 iter_data
= lttng::make_unique
<event_name_iterator_data
>(std::move(iterator
),
218 } catch (const std::bad_alloc
&) {
219 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
220 self_message_iterator
, "Failed to allocate event_name iterator data");
221 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
224 /* Transfer the ownership of iter_data to the iterator. */
225 bt_self_message_iterator_set_data(self_message_iterator
, iter_data
.release());
226 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK
;
229 void event_name_message_iterator_finalize(bt_self_message_iterator
*self_message
)
231 event_name_iterator_data
*iter_data
= static_cast<event_name_iterator_data
*>(
232 bt_self_message_iterator_get_data(self_message
));
234 LTTNG_ASSERT(iter_data
);
238 bt_message_iterator_class_next_method_status
239 event_name_message_iterator_next(bt_self_message_iterator
*self_message_iterator
,
240 bt_message_array_const messages_to_deliver_downstream
,
242 uint64_t *_messages_to_deliver_count
)
244 std::uint64_t messages_to_deliver_count
= 0;
245 auto *iter_data
= static_cast<event_name_iterator_data
*>(
246 bt_self_message_iterator_get_data(self_message_iterator
));
247 const auto& event_name_filter
=
248 *static_cast<class event_name_filter
*>(bt_self_component_get_data(
249 bt_self_message_iterator_borrow_component(self_message_iterator
)));
251 LTTNG_ASSERT(iter_data
);
253 /* Retry until we have at least one message to deliver downstream. */
254 while (messages_to_deliver_count
== 0) {
255 bt_message_array_const upstream_messages
;
256 bt_message_iterator_next_status next_status
;
257 uint64_t upstream_message_count
;
259 next_status
= bt_message_iterator_next(iter_data
->upstream_iterator
.get(),
261 &upstream_message_count
);
262 if (next_status
!= BT_MESSAGE_ITERATOR_NEXT_STATUS_OK
) {
263 return static_cast<bt_message_iterator_class_next_method_status
>(
267 for (std::uint64_t upstream_index
= 0; upstream_index
< upstream_message_count
;
269 lttng::bt2::message_const_ref
upstream_message(
270 upstream_messages
[upstream_index
]);
272 if (message_passes(upstream_message
.get(), event_name_filter
)) {
273 /* Reference transferred to downstream message batch. */
274 messages_to_deliver_downstream
[messages_to_deliver_count
] =
275 upstream_message
.release();
276 messages_to_deliver_count
++;
281 *_messages_to_deliver_count
= messages_to_deliver_count
;
282 return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK
;