sessiond: add variant selector intervals
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 26 Jul 2022 21:06:30 +0000 (17:06 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 8 Dec 2022 14:05:33 +0000 (09:05 -0500)
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 <jeremie.galarneau@efficios.com>
src/bin/lttng-sessiond/field.cpp
src/bin/lttng-sessiond/field.hpp
src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp
src/bin/lttng-sessiond/ust-field-convert.cpp
src/bin/lttng-sessiond/ust-registry-channel.cpp

index df51df488498589f9f4524f6025cce8a4f2366a4..35f4aa0eb4a9b3db1eb636312b433358c213c3e0 100644 (file)
@@ -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<lst::signed_enumeration_type::mapping::range_t::range_integer_t>::accept(
+               lst::type_visitor& visitor) const
+{
+       visitor.visit(*this);
+}
+
+template <>
+void lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::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<decltype(*this)&>(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);
-}
index dec5b103222008200b7adbcb8a019fa2ae3dbd3d..93091572885413e4722bff08358fc7dd13ba1dc8 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <vendor/optional.hpp>
 
+#include <algorithm>
 #include <memory>
 #include <string>
 #include <type_traits>
@@ -77,14 +78,20 @@ private:
 
 class field {
 public:
+       using uptr = std::unique_ptr<field>;
        using cuptr = std::unique_ptr<const field>;
 
        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<MappingIntegerType>;
 
-       enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = delete;
+       enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = default;
        enumeration_mapping(const enumeration_mapping<MappingIntegerType>&& 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 MappingIntegerType>
 class variant_type : public type {
-public:
-       using choices = std::vector<field::cuptr>;
+       static_assert(std::is_same<MappingIntegerType,
+                                       unsigned_enumeration_type::mapping::range_t::
+                                                       range_integer_t>::value ||
+                                       std::is_same<MappingIntegerType,
+                                                       signed_enumeration_type::mapping::range_t::
+                                                                       range_integer_t>::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<const details::enumeration_mapping<MappingIntegerType>, type::cuptr>;
+       using choices = std::vector<choice>;
+
+       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<decltype(*this)&>(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<signed_enumeration_type::mapping::range_t::range_integer_t>& type) = 0;
+       virtual void visit(const variant_type<unsigned_enumeration_type::mapping::range_t::range_integer_t>& type) = 0;
 
 protected:
        type_visitor() = default;
index bccd62737b01374284464c17213e991cc63f56fe..c02addcebdb0d1a902b1c18d7aa75dc8a65c310e 100644 (file)
@@ -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 <class MappingIntegerType>
+       void visit_variant(const lst::variant_type<MappingIntegerType>& type)
        {
                if (type.alignment != 0) {
                        LTTNG_ASSERT(_current_field_name.size() > 0);
@@ -438,8 +439,8 @@ private:
                _bypass_identifier_escape = true;
                for (const auto& field : type._choices) {
                        _description.resize(_description.size() + _indentation_level, '\t');
-                       field->accept(*this);
-                       _description += fmt::format("\n", field->name);
+                       field.second->accept(*this);
+                       _description += fmt::format(" {};\n", field.first.name);
                }
 
                _bypass_identifier_escape = previous_bypass_identifier_escape;
@@ -449,6 +450,16 @@ private:
                _description += "}";
        }
 
+       virtual void visit(const lst::variant_type<lst::signed_enumeration_type::mapping::range_t::range_integer_t>& type) override final
+       {
+               visit_variant(type);
+       }
+
+       virtual void visit(const lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>& type) override final
+       {
+               visit_variant(type);
+       }
+
        lst::type::cuptr create_character_type(enum lst::string_type::encoding encoding)
        {
                _current_integer_encoding_override = encoding;
index 26db5995713228cb0374ae769d7c04f95f8ddcfa..74c41939e3c218a3ce291040d9f49ca253f51cf6 100644 (file)
@@ -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<void(lst::field::cuptr)>;
+using publish_field_fn = std::function<void(lst::field::uptr)>;
 
 /* Look-up field from a field location. */
 using lookup_field_fn = std::function<const lst::field &(const lst::field_location &)>;
@@ -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<const lst::integer_type *>(length_field._type.get());
+                       dynamic_cast<const lst::integer_type *>(&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<lst::structure_type>(alignment, lst::structure_type::fields());
 }
 
+template <class VariantSelectorMappingIntegerType>
+typename lst::variant_type<VariantSelectorMappingIntegerType>::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<VariantSelectorMappingIntegerType>::choices choices;
+       const auto& typed_enumeration = static_cast<
+                       const lst::typed_enumeration_type<VariantSelectorMappingIntegerType>&>(
+                       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<const lst::integer_type *>(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<const lst::enumeration_type *>(&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<lst::signed_enumeration_type::mapping::range_t::range_integer_t>::
+                               choices choices = create_typed_variant_choices<int64_t>(current,
+                                               end, session_attributes, next_ust_ctl_field,
+                                               lookup_field, lookup_root,
+                                               current_field_location_elements, choice_count,
+                                               selector_field);
+
+               return lttng::make_unique<lst::variant_type<int64_t>>(
+                               alignment, std::move(selector_field_location), std::move(choices));
+       } else {
+               lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::
+                               choices choices = create_typed_variant_choices<uint64_t>(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<lst::variant_type<uint64_t>>(
+                               alignment, std::move(selector_field_location), std::move(choices));
        }
-
-       return lttng::make_unique<lst::variant_type>(
-                       alignment, std::move(selector_field_location), std::move(choices));
 }
 
 lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
index b039d3c2fd274c02624e86a873a0877086b100d5..b6092d197217c433f6bd04fbeb5ed3458495568c 100644 (file)
@@ -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::mappings>();
+               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<lst::unsigned_enumeration_type>(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>(
                                                {lst::integer_type::role::EVENT_RECORD_CLASS_ID}));
 
-               lst::variant_type::choices variant_choices;
+               lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::
+                               choices variant_choices;
 
                lst::structure_type::fields compact_fields;
                compact_fields.emplace_back(lttng::make_unique<lst::field>("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<lst::structure_type>(
+               auto compact_type = lttng::make_unique<lst::structure_type>(
                                0, std::move(compact_fields));
-               variant_choices.emplace_back(lttng::make_unique<lst::field>("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<lst::field>("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<lst::structure_type>(0, std::move(extended_fields));
-               variant_choices.emplace_back(lttng::make_unique<lst::field>("extended", std::move(extended)));
+               lst::type::cuptr extended_type = lttng::make_unique<lst::structure_type>(0, std::move(extended_fields));
+               variant_choices.emplace_back(std::move(extended_mapping), std::move(extended_type));
 
-               lst::type::cuptr variant = lttng::make_unique<lst::variant_type>(0,
+               auto variant = lttng::make_unique<lst::variant_type<
+                               lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>>(
+                               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<lst::field>("v", std::move(variant)));
        } else {
                auto enum_mappings = std::make_shared<lst::unsigned_enumeration_type::mappings>();
+               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<lst::unsigned_enumeration_type>(
+               auto choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(
                                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>(
                                                {lst::integer_type::role::EVENT_RECORD_CLASS_ID}));
 
-               lst::variant_type::choices variant_choices;
+               lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::
+                               choices variant_choices;
 
                lst::structure_type::fields compact_fields;
                compact_fields.emplace_back(lttng::make_unique<lst::field>("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::structure_type>(
+               lst::type::cuptr compact_type = lttng::make_unique<lst::structure_type>(
                                0, std::move(compact_fields));
-               variant_choices.emplace_back(
-                               lttng::make_unique<lst::field>("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<lst::field>("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<lst::structure_type>(0, std::move(extended_fields));
-               variant_choices.emplace_back(lttng::make_unique<lst::field>("extended", std::move(extended)));
+               auto extended_type = lttng::make_unique<lst::structure_type>(
+                               0, std::move(extended_fields));
+               variant_choices.emplace_back(std::move(extended_mapping), std::move(extended_type));
 
-               lst::type::cuptr variant = lttng::make_unique<lst::variant_type>(0,
+               auto variant = lttng::make_unique<lst::variant_type<
+                               lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>>(
+                               0,
                                lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER,
                                                {"id"}),
                                std::move(variant_choices));
 
-               event_header_fields.emplace_back(lttng::make_unique<lst::field>("id", std::move(choice_enum)));
+               event_header_fields.emplace_back(
+                               lttng::make_unique<lst::field>("id", std::move(choice_enum)));
                event_header_fields.emplace_back(
                                lttng::make_unique<lst::field>("v", std::move(variant)));
        }
This page took 0.03476 seconds and 4 git commands to generate.