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
) :
60 lttng::utils::random_access_container_wrapper
<const bt_value
*,
62 event_name_set_operations
>(
63 std::move(original
._container
))
67 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()
109 const lttng::bt2::message_iterator_ref upstream_iterator
;
110 const class event_name_filter
& event_name_filter
;
114 bool message_passes(const bt_message
*message
, const event_name_filter
& event_name_filter
)
116 if (bt_message_get_type(message
) != BT_MESSAGE_TYPE_EVENT
) {
120 const bt_event
*event
= bt_message_event_borrow_event_const(message
);
121 const bt_event_class
*event_class
= bt_event_borrow_class_const(event
);
122 const char *event_name
= bt_event_class_get_name(event_class
);
124 if (event_name
== nullptr) {
128 return event_name_filter
.event_name_is_allowed(event_name
);
132 bt_component_class_initialize_method_status
133 event_name_initialize(bt_self_component_filter
*self_comp
,
134 bt_self_component_filter_configuration
*,
135 const bt_value
*params
,
138 bt_self_component_port_input
*input_port
;
139 std::unique_ptr
<class event_name_filter
> event_name_filter
;
141 auto self
= bt_self_component_filter_as_self_component(self_comp
);
142 if (bt_self_component_filter_add_input_port(self_comp
, "in", nullptr, &input_port
) !=
143 BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
144 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self
,
145 "Failed to add input port");
146 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
149 if (bt_self_component_filter_add_output_port(self_comp
, "out", nullptr, nullptr) !=
150 BT_SELF_COMPONENT_ADD_PORT_STATUS_OK
) {
151 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self
,
152 "Failed to add output port");
153 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
156 const auto names_param
= bt_value_map_borrow_entry_value_const(params
, "names");
157 if (names_param
== nullptr) {
158 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
159 self
, "'names' parameter is required");
160 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
164 event_name_set event_names
{ names_param
};
165 if (event_names
.empty()) {
166 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
167 bt_self_component_filter_as_self_component(self_comp
),
168 "'names' parameter must not be empty");
169 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
173 lttng::make_unique
<class event_name_filter
>(input_port
, event_names
);
174 } catch (const std::bad_alloc
&) {
175 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
176 self
, "Failed to allocate memory for private component data");
177 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR
;
178 } catch (const std::exception
& ex
) {
179 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self
, "%s", ex
.what());
180 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
183 /* Ownership of event_name is transferred to the component. */
184 bt_self_component_set_data(self
, event_name_filter
.release());
185 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
;
188 void event_name_finalize(bt_self_component_filter
*self_comp
)
190 class event_name_filter
*event_name_filter
=
191 (class event_name_filter
*) bt_self_component_get_data(
192 bt_self_component_filter_as_self_component(self_comp
));
194 delete event_name_filter
;
197 bt_message_iterator_class_initialize_method_status
198 event_name_message_iterator_initialize(bt_self_message_iterator
*self_message_iterator
,
199 bt_self_message_iterator_configuration
*,
200 bt_self_component_port_output
*)
202 const auto& event_name_filter
=
203 *static_cast<class event_name_filter
*>(bt_self_component_get_data(
204 bt_self_message_iterator_borrow_component(self_message_iterator
)));
206 bt_message_iterator
*raw_iterator
;
207 if (bt_message_iterator_create_from_message_iterator(
208 self_message_iterator
, event_name_filter
.input_port
, &raw_iterator
) !=
209 BT_MESSAGE_ITERATOR_CREATE_FROM_MESSAGE_ITERATOR_STATUS_OK
) {
210 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
213 lttng::bt2::message_iterator_ref
iterator(raw_iterator
);
214 raw_iterator
= nullptr;
216 std::unique_ptr
<event_name_iterator_data
> iter_data
;
218 iter_data
= lttng::make_unique
<event_name_iterator_data
>(std::move(iterator
),
220 } catch (const std::bad_alloc
&) {
221 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
222 self_message_iterator
, "Failed to allocate event_name iterator data");
223 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR
;
226 /* Transfer the ownership of iter_data to the iterator. */
227 bt_self_message_iterator_set_data(self_message_iterator
, iter_data
.release());
228 return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK
;
231 void event_name_message_iterator_finalize(bt_self_message_iterator
*self_message
)
233 event_name_iterator_data
*iter_data
= static_cast<event_name_iterator_data
*>(
234 bt_self_message_iterator_get_data(self_message
));
236 LTTNG_ASSERT(iter_data
);
240 bt_message_iterator_class_next_method_status
241 event_name_message_iterator_next(bt_self_message_iterator
*self_message_iterator
,
242 bt_message_array_const messages_to_deliver_downstream
,
244 uint64_t *_messages_to_deliver_count
)
246 std::uint64_t messages_to_deliver_count
= 0;
247 auto *iter_data
= static_cast<event_name_iterator_data
*>(
248 bt_self_message_iterator_get_data(self_message_iterator
));
249 const auto& event_name_filter
=
250 *static_cast<class event_name_filter
*>(bt_self_component_get_data(
251 bt_self_message_iterator_borrow_component(self_message_iterator
)));
253 LTTNG_ASSERT(iter_data
);
255 /* Retry until we have at least one message to deliver downstream. */
256 while (messages_to_deliver_count
== 0) {
257 bt_message_array_const upstream_messages
;
258 bt_message_iterator_next_status next_status
;
259 uint64_t upstream_message_count
;
261 next_status
= bt_message_iterator_next(iter_data
->upstream_iterator
.get(),
263 &upstream_message_count
);
264 if (next_status
!= BT_MESSAGE_ITERATOR_NEXT_STATUS_OK
) {
265 return static_cast<bt_message_iterator_class_next_method_status
>(
269 for (std::uint64_t upstream_index
= 0; upstream_index
< upstream_message_count
;
271 lttng::bt2::message_const_ref
upstream_message(
272 upstream_messages
[upstream_index
]);
274 if (message_passes(upstream_message
.get(), event_name_filter
)) {
275 /* Reference transferred to downstream message batch. */
276 messages_to_deliver_downstream
[messages_to_deliver_count
] =
277 upstream_message
.release();
278 messages_to_deliver_count
++;
283 *_messages_to_deliver_count
= messages_to_deliver_count
;
284 return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK
;