QoS Profile Inheritance and Composition Guidance

QoS Profile composition is a new feature added to Connext DDS 6. This feature allows QoS Profiles to be constructed from other profiles using composition. Learn the details of this feature and how to properly use it.

1. Introduction to QoS Composition

2. Conventions to follow when using Composition

3. Enforcement of QoS Profile and QoS Profile Snippets conventions

4. Using rtixmloutpututility to visualize the end result of inheritance

1. Introduction to QoS Composition

QoS Profile composition (also referred to as QoS Profile Multiple Inheritance in Connext DDS 6) is an enhancement to the Connext DDS 5 QoS Profile single inheritance mechanism. It allows a QoS Profile to be composed from multiple QoS Profiles. The following sections make some recommendations on how to use QoS Profile composition. These recommendations are meant to supplement the information in the “QoS Profile Inheritance” section of the RTI Connext DDS Core Libraries User’s Manual (current version here, or 6.0.0 version here).

1.1 Connext DDS 5.x - QoS Profile Inheritance Support

Prior to Connext DDS 6, the only way to reuse a QoS Profile configuration was through inheritance. A QoS Profile could inherit from another QoS Profile using the following syntax:

<qos_profile name="Profile1">
        <datawriter_qos>
            <publication_name>
                <name>SampleDataWriter_A</name>
            </publication_name>
        </datawriter_qos>
    </qos_profile>

     <!-- use the base_name attribute to inherit from another profile -->
     <qos_profile name="MyDerivedProfile" base_name="Profile1">
         <datawriter_qos>
             <batch>
                 <enable>true</enable>
                 <max_samples>100</max_samples>
                 <max_data_bytes>LENGTH_UNLIMITED</max_data_bytes>
            </batch>
         </datawriter_qos>
     </qos_profile>

Figure 1: Definition of a QoS Profile that inherits from another Profile 

Figure 1 shows how the QoS Profile called MyDerivedProfile is constructed via inheritance from the QoS Profile Profile1. The profile MyDerivedProfile inherits Profile1 by referencing the base profile in the attribute base_name="Profile1". As a result, the profile MyDerivedProfile first initializes all its QoS policies with the values obtained from Profile1. Then it applies any policies explicitly listed in its own definition to override the initialized values. In this example, MyDerivedProfile only modifies the BatchQos policy on the DataWriter QoS.

If a QoS Profile definition does not specify the base_name attribute, then it is initialized from the builtin defaults provided by Connext DDS.

The QoS Profile inheritance mechanism provided by Connext prior to version 6 allows the use of QoS Profiles to define new profiles. This mechanism was used to create libraries of profiles for common application use cases. For example, see this RTI Community article on using the built in QoS Profiles.

1.2 Limitations of QoS Profile Inheritance

While useful, the restriction to initialize a QoS Profile from a single base QoS Profile was also limiting. For example, assume you have the following configuration:

Figure 2: Single inheritance example

If you wanted to incorporate monitoring into the QoS Profiles app_1 and app_2, the only option with single inheritance would be to create two new QoS Profiles, each inheriting from app_1 and app_2 respectively, and to copy the monitoring XML configuration into each of the two new QoS Profiles. This results in significant XML code duplication and leads to maintainability issues.

 

Figure 3: Duplication of monitoring configuration

1.3 Connext DDS 6 - QoS Composition Support

Connext 6 preserves the single inheritance approach offered by previous versions of Connext. When a QoS Profile is defined, it is still possible to base that definition on another QoS Profile using the base_name attribute, the same way as was done in previous versions of Connext.

In addition to single inheritance, Connext 6 now also supports defining a QoS Profile via composition of one or more QoS Profiles. These profiles, should be minimal and define a single aspect of the functionality. They will be called QoS Profile Snippets.

In the example above, you could add the monitoring configuration to the new QoS Profiles app_mon_1 and app_mon_2 by referring to a QoS Profile Snippet that configures monitoring.

Figure 4: Monitoring Configuration with QoS Profile Snippet

1.3.1 QoS Profile Snippets

QoS Profile Snippets are small pieces of well-formed, reusable XML QoS that configure a single aspect of QoS, such as enabling monitoring or security. They are intended to be composed into other QoS Profile Snippets and QoS Profiles.  As we shall see, the syntax used to define a QoS Profile Snippet is the same as that of a QoS Profile, but the intent and usage are different.

The following is an example of the syntax used to define and use QoS Profile Snippets:

<!-- This is a QoS Profile Snippet -->
    <qos_profile name="Snippet1">
        <datareader_qos>
             <reliability>
                 <kind>RELIABLE_RELIABILITY</kind>
             </reliability>
        </datareader_qos>
    </qos_profile>
    
    <!-- This is a QoS Profile Snippet -->
    <qos_profile name="Snippet2">
       <datareader_qos>
            <durability>
                <kind>TRANSIENT_LOCAL_DURABILITY</kind>
            </durability>
        </datareader_qos>
    </qos_profile> 
    
    <qos_profile name="Profile1">
        <datawriter_qos>
             <publication_name>
                 <name>SampleDataWriter_A</name>
             </publication_name>
        </datawriter_qos>
    </qos_profile> 
    
    <!-- The definition of this QoS Profile uses the Snippets -->
    <qos_profile name="MyDerivedAndComposedProfile" base_name="Profile1">
        <base_name>
             <element>Snippet1</element>
             <element>Snippet2</element>
         </base_name>
         <datareader_qos>
             <history>
                 <kind>KEEP_LAST_HISTORY_QOS</kind>
                 <depth>6</depth>
             </history>
         </datareader_qos>
     </qos_profile>

Figure 5: Definition of a QoS Profile that inherits from another Profile and uses composition to weave in polices from two QoS Snippets

Figure 5 shows how the QoS Profile with configuration name MyDerivedAndComposedProfile is constructed by inheriting from the Profile1 profile (same feature available prior to Connext 6) and additionally by composing the QoS Snippets Snippet1 and Snippet2.

1.3.2 How do inheritance and composition work together?

The process followed when inheriting and composing from other profiles is as follows:

  • First, the QoS policies are initialized from those in the base profile, using the base_name attribute of the  <qos_profile> tag. If the base_name attribute is not present, then the policies are initialized from the builtin defaults defined by Connext. This behavior is identical to previous versions of Connext.
  • Next, the policies are overridden with those defined in the QoS Profile Snippets listed inside the <base_name> XML tag. The snippets are applied in the order in which they appear. So the first snippet ( Snippet1 in the example above) overrides the policies that were set from the inherited base profile (Profile1 in the example), the second snippet ( Snippet2 in the example) overrides whatever was the result of applying Snippet1, and so on.
  • Finally, the policies that appear explicitly as elements in the profile are applied. These override the policies set by the base profile and the snippets. In this example, a KEEP_LAST_HISTORY_DEPTH of 6 overrides whatever was set by the base profile and the snippets.

Basically, the recommendation is to inherit a QoS Profile, but overlay one or more Qos Snippets. You inherit a QoS Profile because you want to subsume the complete definition of the QoS policies for a particular use case. You overlay Snippets onto a Profile so that you override only what you expect: for instance, only what is logically associated with monitoring.

2. Conventions to follow when using Composition

XML QoS Profile inheritance and composition provide a powerful way to define configurations, allowing flexibility and reusability. It is important to understand the underlying mechanics and follow the conventions described in this document to maximize usability and avoid unexpected results.

These conventions are illustrated in Figure 6 and further described in the sections that follow.

Figure 6: Best Practices for Inheritance and Composition

2.1 Differentiate between QoS Profiles and QoS Profile Snippets

When defining a QoS Profile, decide whether you are:

  • Creating a QoS Profile intended to create DDS Entities and/or fully define their QoS.
  • Creating a QoS Profile Snippet intended as a reusable block to be composed in the definition of QoS Profiles and other QoS Profile Snippets.

These two options are fundamentally different.

A QoS Profile is intended to define the QoS policies used to create a DDS Entity. Therefore, it should match a specific application use case (e.g., sending alarms, or streaming periodic data). Moreover, because the QoS Profile will be used to create a DDS Entity, it implicitly defines values for all the QoS Policies that apply to the entity.

When defining a QoS Profile, choose the builtin QoS Profile that most closely matches your use case. Use that builtin profile as a base profile. For example:

<qos_profile name="MyProfile" base_name="BuiltinQosLibExp::Pattern.AlarmEvent">
      <!-- modify the profile composing QoS Profile Snippets -->
      <!-- modify the profile overriding the policies/policy attributes explicitly -->
     </qos_profile> 

Give the QoS Profile a name that makes it clear its intended use, as well as the fact that it is a QoS Profile (instead of a QoS Profile Snippet). For example, use “Profile” as a suffix in the name of the QoS Profile.

A QoS Profile Snippet is intended as a generic block of QoS policies for composition into QoS Profiles and other QoS Profile Snippets . For example, configuring monitoring, configuring Security, and configuring a FlowController are good uses for QoS Profile Snippets.

QoS Profile Snippets should focus on a single aspect of QoS policy and try not to set unrelated policies. This maximizes composability, avoiding interfering with policies set by other QoS Profile Snippets.

QoS Profile Snippets should be generic and reusable across systems and deployments. Therefore, it does not make sense to constrain their applicability using the <topic_filter> element within their definition. Doing so may also result in conflict with Topic filters set on Profiles that use those Snippets.

Give the Snippet a name that makes clear its intended use, as well as the fact that it is a QoS Profile Snippet (not a regular QoS Profile). For example, use “Snippet” as a suffix in the name of the Snippet.

2.2 Use QoS Profiles for inheritance only, never composition

Aside from its use for creating DDS Entities, a QoS Profile may be used as the base definition of another QoS Profile. For example:

<qos_profile name="MyDerivedProfile" base_name="MyBaseProfile">
       ...
    </qos_profile> 

When used for inheritance, the derived profile is initialized with the policies of the base profile.

A profile should never be used for composition. That is, it should not be referenced within the <base_name> element:

<qos_profile name="MyDerivedProfile">
      <base_name>
         <element>MyBaseProfile</element> <!-- never do this -->
       </base_name>
     </qos_profile> 

The reason for this is that a QoS Profile implicitly defines all the QoS policies. So using it for composition would have the unintended effect of potentially overriding all the policies.

2.3 Use QoS Profile Snippets for composition, never inheritance

QoS Profile Snippets are small pieces of well-formed XML QoS intended to configure a single aspect of QoS . They are intended to be composed into other QoS Profile Snippets and Profiles.

The proper way to use them is for the composition of other QoS Profiles and Profile Snippets. Therefore, they must only appear within the <base_name> element. For example:

<qos_profile name="MyComposedProfile " base_name="MyBaseProfile">
      <base_name>
         <element>Snippet1</element>
         <element>Snippet2</element>
         <element>Snippet3</element>
      </base_name>
       ...
    </qos_profile> 
    
    <qos_profile name="MyComposedSnippet">
      <base_name>
         <element>Snippet1</element>
         <element>Snippet2</element>
         <element>Snippet3</element>
       </base_name>
       ...
     </qos_profile> 

Do not use a QoS Profile Snippet for inheritance. For example:

<!-- do not do this -->
    <qos_profile name="MyComposedProfile" base_name="Snippet1">
      <base_name>
         <element>Snippet2</element>
         <element>Snippet3</element>
       </base_name>
       ...
    </qos_profile>

The reason to not use a QoS Profile Snippet for inheritance is that the very intent of a QoS Profile Snippet is to define only one aspect. If you use it for initializing another Qos Profile, you are using something that was not intended to be used as a full definition and may have overlooked the proper configuration of certain policies for your system.

2.4 Use QoS Profiles to create DDS Entities, not QoS Profile Snippets

The QoS configuration of DDS Entities can be specified using QoS Profiles. This is a convenient mechanism that allows separation of configuration from the functional logic of your application.

The Connext DDS API contains several operations that reference QoS Profiles by name. These operations are used to either create DDS Entities with the QoS policies referenced by the profile name, or to initialize the Entity QoS structure with the QoS policies referenced by the profile.  Either way, these operations should not be called using a QoS Snippet name as the reference.

See the Connext Users Manual chapter on configuring QoS and Language API Reference Documentation for your Programming Language (e.g. Traditional C++ ) for details on these operations.

2.5 Keep QoS Snippets generic and reusable

QoS Profile Snippets should be developed with reuse in mind and should not use the <topic_filter> element within the definition of the QoS Snippet.

<!-- do not do this -->
    <qos_profile name="MySnippet">
        <datawriter_qos topic_filter="Alarm">
            <reliability>
                <kind>RELIABLE_RELIABILITY</kind>
            </reliability>
       </datawriter_qos> 
       <datawriter_qos topic_filter="SensorUpdate">
           <reliability>
               <kind>BEST_EFFORTS_RELIABILITY</kind>
           </reliability>
      </datawriter_qos>
       ...
    </qos_profile>

The reason to not use <topic_filter> is that this element conditionally defines the QoS Profile depending on the Topic name associated with the Entity being created or configured. Since the QoS Snippet is not intended to create or configure DDS Entities directly (see Use QoS Profiles to create DDS Entities, not QoS Profile Snippets) it does not make sense to use the <topic_filter> element in its definition.

3. Enforcement of QoS Profile and QoS Profile Snippets conventions

Connext uses the same syntax for the creation of QoS Profiles and QoS Profile Snippets. Therefore, it does not enforce the conventions described in this document. That is, Connext will not detect or prevent violation of these conventions (e.g., if you use a QoS Profile for composition); however, following these conventions is strongly encouraged to avoid unexpected results. In addition, future versions of Connext may introduce different syntax that allows differentiating QoS Profiles from QoS Profile Snippets and enforce the conventions. If you follow these conventions now, you can continue using them without violating future syntax.

4. Visualization of the end result of applying inheritance and composition to build a QoS Profile

The final value for a QoS policy in a QoS Profile using inheritance and QoS Profile Snippet composition can be visualized at run-time using RTI Monitor and RTI Administration Console.

You can also use rtixmloutpututility to visualize the end result at creation time.

rtixmloutpututility allows you to see the final QoS values your entities will receive after all the inheritance and composition is resolved. Here is an example usage of this utility:

$ ./rtixmloutpututility
        -qosFile '/home/xxx/Documents/Tests/CORE-9446/USER_QOS_PROFILES.xml;/home/xxx/Documents/Tests/CORE-1375/USER_QOS_PROFILES.xml'
         -profilePath Data_Library::Data_Profile
         -outputFile Dummy.txt
         -qosTag participant_qos/property

To get this utility, including more information about its options and usage, please see: https://github.com/rticommunity/rticonnextdds-xml-output-utility