From 9efff7e744f4b4b3fbe37de5fece3b59fdeb4b00 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 26 Jul 2022 17:06:30 -0400 Subject: [PATCH 1/1] sessiond: add variant selector intervals MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit In CTF 2, variant options are chosen using a set of ranges. This differs from CTF 1.8 (and the current API) which assumed that a variant had options that perfectly matched the selector enumeration's mappings. Add integer mappings to variants and also carry a choice name that becomes the name used by the TSDL producer. Change-Id: Ib31cf9cc211dad36759bd73dc722c49d634c666b Signed-off-by: Jérémie Galarneau --- src/bin/lttng-sessiond/field.cpp | 56 ++++++----- src/bin/lttng-sessiond/field.hpp | 63 ++++++++++-- .../tsdl-trace-class-visitor.cpp | 17 +++- src/bin/lttng-sessiond/ust-field-convert.cpp | 97 +++++++++++++++---- .../lttng-sessiond/ust-registry-channel.cpp | 52 ++++++---- 5 files changed, 209 insertions(+), 76 deletions(-) diff --git a/src/bin/lttng-sessiond/field.cpp b/src/bin/lttng-sessiond/field.cpp index df51df488..35f4aa0eb 100644 --- a/src/bin/lttng-sessiond/field.cpp +++ b/src/bin/lttng-sessiond/field.cpp @@ -66,6 +66,9 @@ bool lst::type::operator!=(const lst::type& other) const noexcept lst::field::field(std::string in_name, lst::type::cuptr in_type) : name{std::move(in_name)}, _type{std::move(in_type)} { + if (!_type) { + LTTNG_THROW_ERROR(fmt::format("Invalid type used to create field: field name = `{}`", name)); + } } void lst::field::accept(lst::field_visitor& visitor) const @@ -78,6 +81,20 @@ bool lst::field::operator==(const lst::field& other) const noexcept return name == other.name && *_type == *other._type; } +lst::type::cuptr lst::field::move_type() noexcept +{ + return std::move(_type); +} + +const lst::type &lst::field::get_type() const +{ + if (_type) { + return *_type; + } else { + LTTNG_THROW_ERROR(fmt::format("Invalid attempt to access field type after transfer: field name = `{}`", name)); + } +} + lst::integer_type::integer_type(unsigned int in_alignment, enum lst::byte_order in_byte_order, unsigned int in_size, @@ -192,6 +209,20 @@ void lst::unsigned_enumeration_type::accept(type_visitor& visitor) const } /* namespace sessiond */ } /* namespace lttng */ +template <> +void lst::variant_type::accept( + lst::type_visitor& visitor) const +{ + visitor.visit(*this); +} + +template <> +void lst::variant_type::accept( + lst::type_visitor& visitor) const +{ + visitor.visit(*this); +} + lst::array_type::array_type(unsigned int in_alignment, type::cuptr in_element_type) : type(in_alignment), element_type{std::move(in_element_type)} { @@ -359,28 +390,3 @@ void lst::structure_type::accept(type_visitor& visitor) const { visitor.visit(*this); } - -lst::variant_type::variant_type(unsigned int in_alignment, - field_location in_selector_field_location, - choices in_choices) : - type(in_alignment), - selector_field_location{std::move(in_selector_field_location)}, - _choices -{std::move(in_choices)} -{ -} - -bool lst::variant_type::_is_equal(const type& base_other) const noexcept -{ - const auto &other = static_cast(base_other); - - return this->selector_field_location == other.selector_field_location && - fields_are_equal(this->_choices -, other._choices -); -} - -void lst::variant_type::accept(type_visitor& visitor) const -{ - visitor.visit(*this); -} diff --git a/src/bin/lttng-sessiond/field.hpp b/src/bin/lttng-sessiond/field.hpp index dec5b1032..930915728 100644 --- a/src/bin/lttng-sessiond/field.hpp +++ b/src/bin/lttng-sessiond/field.hpp @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -77,14 +78,20 @@ private: class field { public: + using uptr = std::unique_ptr; using cuptr = std::unique_ptr; field(std::string name, type::cuptr type); void accept(field_visitor& visitor) const; bool operator==(const field& other) const noexcept; + const type& get_type() const; + type::cuptr move_type() noexcept; + const std::string name; - const type::cuptr _type; + +private: + type::cuptr _type; }; class integer_type : public type { @@ -198,7 +205,7 @@ class enumeration_mapping { public: using range_t = enumeration_mapping_range; - enumeration_mapping(const enumeration_mapping& other) = delete; + enumeration_mapping(const enumeration_mapping& other) = default; enumeration_mapping(const enumeration_mapping&& other) : name{std::move(other.name)}, range{other.range} { @@ -406,22 +413,57 @@ private: virtual bool _is_equal(const type& base_other) const noexcept override final; }; +template class variant_type : public type { -public: - using choices = std::vector; + static_assert(std::is_same::value || + std::is_same::value, + "Variant mapping integer type must be one of those allowed by typed_enumeration_type"); - variant_type(unsigned int alignment, - field_location selector_field_location, - choices in_choices); +public: + using choice = std::pair, type::cuptr>; + using choices = std::vector; + + variant_type(unsigned int in_alignment, + field_location in_selector_field_location, + choices in_choices) : + type(in_alignment), + selector_field_location{std::move(in_selector_field_location)}, + _choices{std::move(in_choices)} + { + } virtual void accept(type_visitor& visitor) const override final; const field_location selector_field_location; const choices _choices; -; private: - virtual bool _is_equal(const type& base_other) const noexcept override final; + static bool _choices_are_equal(const choices& a, const choices& b) + { + if (a.size() != b.size()) { + return false; + } + + return true; + + return std::equal(a.cbegin(), a.cend(), b.cbegin(), + [](const choice& choice_a, const choice& choice_b) { + return choice_a.first == choice_b.first && + *choice_a.second == *choice_b.second; + }); + } + + virtual bool _is_equal(const type& base_other) const noexcept override final + { + const auto& other = static_cast(base_other); + + return selector_field_location == other.selector_field_location && + _choices_are_equal(_choices, other._choices); + } }; class field_visitor { @@ -448,7 +490,8 @@ public: virtual void visit(const static_length_string_type& type) = 0; virtual void visit(const dynamic_length_string_type& type) = 0; virtual void visit(const structure_type& type) = 0; - virtual void visit(const variant_type& type) = 0; + virtual void visit(const variant_type& type) = 0; + virtual void visit(const variant_type& type) = 0; protected: type_visitor() = default; diff --git a/src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp b/src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp index d007c530b..835c57905 100644 --- a/src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp +++ b/src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp @@ -146,7 +146,7 @@ private: _current_field_name.push(_bypass_identifier_escape ? field.name : escape_tsdl_identifier(field.name)); - field._type->accept(*this); + field.get_type().accept(*this); _description += " "; _description += _current_field_name.top(); _current_field_name.pop(); @@ -411,7 +411,8 @@ private: _description += "}"; } - virtual void visit(const lst::variant_type& type) override final + template + void visit_variant(const lst::variant_type& type) { if (type.alignment != 0) { LTTNG_ASSERT(_current_field_name.size() > 0); @@ -438,7 +439,7 @@ private: _bypass_identifier_escape = true; for (const auto& field : type._choices) { _description.resize(_description.size() + _indentation_level, '\t'); - field->accept(*this); + field.second->accept(*this); _description += "\n"; } @@ -449,6 +450,16 @@ private: _description += "}"; } + virtual void visit(const lst::variant_type& type) override final + { + visit_variant(type); + } + + virtual void visit(const lst::variant_type& type) override final + { + visit_variant(type); + } + lst::type::cuptr create_character_type(enum lst::string_type::encoding encoding) { _current_integer_encoding_override = encoding; diff --git a/src/bin/lttng-sessiond/ust-field-convert.cpp b/src/bin/lttng-sessiond/ust-field-convert.cpp index 4911db0e5..74c41939e 100644 --- a/src/bin/lttng-sessiond/ust-field-convert.cpp +++ b/src/bin/lttng-sessiond/ust-field-convert.cpp @@ -38,7 +38,7 @@ public: }; /* Used to publish fields on which a field being decoded has an implicit dependency. */ -using publish_field_fn = std::function; +using publish_field_fn = std::function; /* Look-up field from a field location. */ using lookup_field_fn = std::function; @@ -510,7 +510,7 @@ lst::type::cuptr create_sequence_nestable_type_from_ust_ctl_fields( /* Validate existence of length field (throws if not found). */ const auto &length_field = lookup_field(length_field_location); const auto *integer_selector_field = - dynamic_cast(length_field.type_.get()); + dynamic_cast(&length_field.get_type()); if (!integer_selector_field) { LTTNG_THROW_PROTOCOL_ERROR("Invalid selector field type referenced from sequence: expected integer or enumeration"); } @@ -567,6 +567,57 @@ lst::type::cuptr create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_ return lttng::make_unique(alignment, lst::structure_type::fields()); } +template +typename lst::variant_type::choices create_typed_variant_choices( + const lttng_ust_ctl_field *current, + const lttng_ust_ctl_field *end, + const session_attributes& session_attributes, + const lttng_ust_ctl_field **next_ust_ctl_field, + lookup_field_fn lookup_field, + lst::field_location::root lookup_root, + lst::field_location::elements& current_field_location_elements, + unsigned int choice_count, + const lst::field& selector_field) +{ + typename lst::variant_type::choices choices; + const auto& typed_enumeration = static_cast< + const lst::typed_enumeration_type&>( + selector_field.get_type()); + + for (unsigned int i = 0; i < choice_count; i++) { + create_field_from_ust_ctl_fields( + current, end, session_attributes, next_ust_ctl_field, + [&choices, typed_enumeration, &selector_field]( + lst::field::uptr field) { + /* + * Find the enumeration mapping that matches the + * field's name. + */ + const auto mapping_it = std::find_if( + typed_enumeration._mappings->begin(), + typed_enumeration._mappings->end(), + [&field](const typename std::remove_reference< + decltype(typed_enumeration)>::type:: + mapping& mapping) { + return mapping.name == field->name; + }); + + if (mapping_it == typed_enumeration._mappings->end()) { + LTTNG_THROW_PROTOCOL_ERROR(fmt::format( + "Invalid variant choice: `{}` does not match any mapping in `{}` enumeration", + field->name, selector_field.name)); + } + + choices.emplace_back(*mapping_it, field->move_type()); + }, + lookup_field, lookup_root, current_field_location_elements); + + current = *next_ust_ctl_field; + } + + return choices; +} + lst::type::cuptr create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current, const lttng_ust_ctl_field *end, const session_attributes& session_attributes, @@ -607,27 +658,37 @@ lst::type::cuptr create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_fi /* Validate existence of selector field (throws if not found). */ const auto &selector_field = lookup_field(selector_field_location); - const auto *integer_selector_field = dynamic_cast(selector_field.type_.get()); - if (!integer_selector_field) { - LTTNG_THROW_PROTOCOL_ERROR("Invalid selector field type referenced from variant: expected integer or enumeration"); + const auto *enumeration_selector_type = + dynamic_cast(&selector_field.get_type()); + if (!enumeration_selector_type) { + LTTNG_THROW_PROTOCOL_ERROR("Invalid selector field type referenced from variant: expected enumeration"); } + const bool selector_is_signed = enumeration_selector_type->signedness_ == + lst::integer_type::signedness::SIGNED; + /* Choices follow. next_ust_ctl_field is updated as needed. */ - lst::variant_type::choices choices; - for (unsigned int i = 0; i < choice_count; i++) { - create_field_from_ust_ctl_fields( - current, end, session_attributes, next_ust_ctl_field, - [&choices](lst::field::cuptr field) { - choices.emplace_back(std::move(field)); - }, - lookup_field, - lookup_root, current_field_location_elements); + if (selector_is_signed) { + lst::variant_type:: + choices choices = create_typed_variant_choices(current, + end, session_attributes, next_ust_ctl_field, + lookup_field, lookup_root, + current_field_location_elements, choice_count, + selector_field); + + return lttng::make_unique>( + alignment, std::move(selector_field_location), std::move(choices)); + } else { + lst::variant_type:: + choices choices = create_typed_variant_choices(current, + end, session_attributes, next_ust_ctl_field, + lookup_field, lookup_root, + current_field_location_elements, choice_count, + selector_field); - current = *next_ust_ctl_field; + return lttng::make_unique>( + alignment, std::move(selector_field_location), std::move(choices)); } - - return lttng::make_unique( - alignment, std::move(selector_field_location), std::move(choices)); } lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current, diff --git a/src/bin/lttng-sessiond/ust-registry-channel.cpp b/src/bin/lttng-sessiond/ust-registry-channel.cpp index b039d3c2f..b6092d197 100644 --- a/src/bin/lttng-sessiond/ust-registry-channel.cpp +++ b/src/bin/lttng-sessiond/ust-registry-channel.cpp @@ -85,9 +85,12 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas if (header_type == lst::stream_class::header_type::COMPACT) { auto enum_mappings = std::make_shared(); + lst::unsigned_enumeration_type::mapping compact_mapping{ + "compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30)}; + lst::unsigned_enumeration_type::mapping extended_mapping{"extended"}; - enum_mappings->emplace_back("compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30)); - enum_mappings->emplace_back("extended"); + enum_mappings->emplace_back(compact_mapping); + enum_mappings->emplace_back(extended_mapping); lst::type::cuptr choice_enum = lttng::make_unique(1, trace_abi.byte_order, 5, lst::integer_type::base::DECIMAL, @@ -95,7 +98,8 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas std::initializer_list( {lst::integer_type::role::EVENT_RECORD_CLASS_ID})); - lst::variant_type::choices variant_choices; + lst::variant_type:: + choices variant_choices; lst::structure_type::fields compact_fields; compact_fields.emplace_back(lttng::make_unique("timestamp", @@ -106,9 +110,9 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas role>({lst::integer_type::role:: DEFAULT_CLOCK_TIMESTAMP})))); - lst::type::cuptr compact = lttng::make_unique( + auto compact_type = lttng::make_unique( 0, std::move(compact_fields)); - variant_choices.emplace_back(lttng::make_unique("compact", std::move(compact))); + variant_choices.emplace_back(std::move(compact_mapping), std::move(compact_type)); lst::structure_type::fields extended_fields; extended_fields.emplace_back(lttng::make_unique("id", @@ -128,10 +132,12 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas role>({lst::integer_type::role:: DEFAULT_CLOCK_TIMESTAMP})))); - lst::type::cuptr extended = lttng::make_unique(0, std::move(extended_fields)); - variant_choices.emplace_back(lttng::make_unique("extended", std::move(extended))); + lst::type::cuptr extended_type = lttng::make_unique(0, std::move(extended_fields)); + variant_choices.emplace_back(std::move(extended_mapping), std::move(extended_type)); - lst::type::cuptr variant = lttng::make_unique(0, + auto variant = lttng::make_unique>( + 0, lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER, {"id"}), std::move(variant_choices)); @@ -141,17 +147,20 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas lttng::make_unique("v", std::move(variant))); } else { auto enum_mappings = std::make_shared(); + lst::unsigned_enumeration_type::mapping compact_mapping{"compact", + lst::unsigned_enumeration_type::mapping::range_t(0, 65534)}; + lst::unsigned_enumeration_type::mapping extended_mapping{"extended"}; + enum_mappings->emplace_back(compact_mapping); + enum_mappings->emplace_back(extended_mapping); - enum_mappings->emplace_back("compact", lst::unsigned_enumeration_type::mapping::range_t(0, 65534)); - enum_mappings->emplace_back("extended"); - - lst::type::cuptr choice_enum = lttng::make_unique( + auto choice_enum = lttng::make_unique( trace_abi.uint16_t_alignment, trace_abi.byte_order, 16, lst::integer_type::base::DECIMAL, std::move(enum_mappings), std::initializer_list( {lst::integer_type::role::EVENT_RECORD_CLASS_ID})); - lst::variant_type::choices variant_choices; + lst::variant_type:: + choices variant_choices; lst::structure_type::fields compact_fields; compact_fields.emplace_back(lttng::make_unique("timestamp", @@ -163,10 +172,9 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas role>({lst::integer_type::role:: DEFAULT_CLOCK_TIMESTAMP})))); - lst::type::cuptr compact = lttng::make_unique( + lst::type::cuptr compact_type = lttng::make_unique( 0, std::move(compact_fields)); - variant_choices.emplace_back( - lttng::make_unique("compact", std::move(compact))); + variant_choices.emplace_back(std::move(compact_mapping), std::move(compact_type)); lst::structure_type::fields extended_fields; extended_fields.emplace_back(lttng::make_unique("id", @@ -186,15 +194,19 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas role>({lst::integer_type::role:: DEFAULT_CLOCK_TIMESTAMP})))); - lst::type::cuptr extended = lttng::make_unique(0, std::move(extended_fields)); - variant_choices.emplace_back(lttng::make_unique("extended", std::move(extended))); + auto extended_type = lttng::make_unique( + 0, std::move(extended_fields)); + variant_choices.emplace_back(std::move(extended_mapping), std::move(extended_type)); - lst::type::cuptr variant = lttng::make_unique(0, + auto variant = lttng::make_unique>( + 0, lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER, {"id"}), std::move(variant_choices)); - event_header_fields.emplace_back(lttng::make_unique("id", std::move(choice_enum))); + event_header_fields.emplace_back( + lttng::make_unique("id", std::move(choice_enum))); event_header_fields.emplace_back( lttng::make_unique("v", std::move(variant))); } -- 2.34.1