3.1. General Compatibility 7.7.0

This section describes compatibility issues that affect an upgrade to 7.7.0. It describes general, wire, and other compatibility issues between Connext 7.7.0 and previous releases.

Unless noted otherwise, the issues in this section do not apply to RTI Connext Micro.

Attention

For important information on new and removed features in release 7.7.0, start with the Connext What’s New for 7.7.0.

See Product-Specific Compatibility 7.7.0 for specific issues.

See RTI Connext Performance Benchmarks for performance details in this release. See also Library Size and Memory Consumption.

3.1.1. Wire Compatibility

3.1.1.1. RTPS Versions

See Compatibility, in the RTI Connext DDS Core Libraries Release Notes, for information about the RTPS versions supported for each Connext release.

3.1.1.2. Best-effort DataReader from before 6.1.0 cannot receive MultiChannel RTPS fragmented data from synchronous DataWriter in 7.7.0

You cannot have a best-effort DataReader from a release below 6.1.0 receiving MultiChannel RTPS fragmented data from a 7.7.0 DataWriter publishing synchronously. This backward compatibility had to be broken because of the fix for RTI Issue ID CORE-14668.

3.1.1.3. DataReader in 7.7.0 may not interoperate with DataWriter in previous release when using XCDR and mutable unions

Consider the following scenario:

  • One DomainParticipant (DP1) is using 7.7.0.

  • One DomainParticipant (DP2) is using

    • a previous release (version 6.0.0 or above), and

    • Dynamic Data or a language API other than Java.

In 7.7.0, a union’s discriminator value may not select any member in the union. When this is the case, and when the union is mutable, the XCDR serialization and deserialization of the union are different between DP1 and DP2 by default. If the union is part of a data type that has other members that appear after the union, then this difference will cause lack of interoperability between the two DomainParticipants. To enable interoperability, you must change DP1 as described in Extensible Types Compliance Mask in the RTI Connext Core Libraries Extensible Types Guide. The environment variable NDDS_XTYPES_COMPLIANCE_MASK or the input of set_xtypes_mask() must exclude the bit 0x00000080 (sentinel_in_empty_union()).

3.1.1.4. Configure compatibility with Java keyhash calculation in previous releases

In previous releases, the Java keyhash calculation of mutable types in XCDR (Extensible CDR version 1) was not compliant with the OMG ‘Extensible and Dynamic Topic Types for DDS’ specification, version 1.4, when either of the following conditions was met:

  • The type’s maximum serialized size exceeded 65 KB, and the key was not primitive.

  • At least one key member had a member ID greater than 16128.

In 7.7.0, the keyhash calculation for Java has been corrected under these conditions. This change ensures that Java now generates the same keyhash as the other language bindings. This fix causes the Java API in 7.7.0 and later releases to generate a different keyhash than the Java API in earlier releases under the above conditions.

If you need to maintain compatibility with keyhashes generated by Java in earlier releases, you can restore the previous behavior by modifying the Extensible Types compliance mask, by setting the java_keyhash_750() bit (0x00000200), to enable the legacy keyhash calculation (and not be compatible with the specification). By default, the bit is not set (and is compatible with the specification).

For example, to restore the previous behavior, you could set the mask in Java like this:

import com.rti.ndds.config.Compliance;
import com.rti.ndds.config.Compliance.XTypesMask;

XTypesMask xTypesComplianceMask = Compliance.get_xtypes_mask();
xTypesComplianceMask.set_bit(XTypesMask.JAVA_KEYHASH_750_BIT);
Compliance.set_xtypes_mask(xTypesComplianceMask);

See Extensible Types Compliance Mask in the RTI Connext Core Libraries Extensible Types Guide for more information.

3.1.1.5. RTPS Header Extension timestamp clock has changed

The RTPS Header Extension timestamp used to be populated using an internal clock set by dds.clock.internal_clock. This could lead to the timestamp being populated with an invalid value (from the perspective of the remote host), if the internal clock was set to “monotonic”. Starting in this release, the clock used to generate the RTPS Header Extension timestamp has changed to the external clock, dds.clock.external_clock.

Your application could be affected by this fix if you use the RTPS Header Extension timestamp and rely on its value to be “monotonic”. If you do, consider setting the dds.clock.external_clock property to “monotonic”. Keep in mind that this change would also affect the external clock used in other places. See Configuring the Clock per DomainParticipant for details.

Note that this change does not affect the RTPS Timestamp submessage, which already used and continues to use the external clock.

3.1.2. Type System Compatibility

3.1.2.1. Assignability of 8-bit types

Previously, int8, uint8, and octet were considered assignable out-of- the-box. In this release, int8, uint8, and octet are treated as distinct types and are no longer considered assignable to one another out-of- the-box. If a DataWriter uses int8 and a DataReader uses octet, they will fail to match, resulting in an INCONSISTENT_TOPIC status.

To get the old behavior back, you must enable TypeObject v1 propagation (the previous default) instead of TypeObject v2 (the new default). You can do this by setting the DomainParticipantResourceLimitsQosPolicy::type_object_max_serialized_length to a value large enough for your types and removing the TYPE_LOOKUP_SERVICE_CHANNEL from the DiscoveryConfigQosPolicy::enabled_builtin_endpoints mask.

<domain_participant_qos>
    <resource_limits>
        <type_object_max_serialized_length>8192</type_object_max_serialized_length>
    </resource_limits>
    <discovery_config>
        <enabled_builtin_channels>SERVICE_REQUEST_CHANNEL</enabled_builtin_channels>
    </discovery_config>
</domain_participant_qos>

If a participant receives TypeObject v1 types from an old application, it will apply the old assignability rules (that is, all 8-bit types will be considered assignable), even if the local participant itself has enabled TypeObject v2.

For more information, see:

3.1.2.2. Incompatibility between Python API and other APIs when using int8 type

This release fixes an issue (PY-190) with communication between Python and the rest of the language APIs when using an int8 type. The int8 types were incorrectly treated as characters instead of octets, leading to communication failures.

This fix changed how the Python API defines and accesses int8 values, using an int8 (signed-octet) type instead of char. As a result, when using an int8 type, Python applications in 7.3.0 or 7.4.0 will not interoperate with Python applications in later releases that include this fix.

This change also removed the Python set_int8 methods that accepted a char argument.

In this release, you can set the bit python_int8_730() bit(0x00000400) in the Extensible Types compliance mask to communicate with the Python API in previous releases (but not be compliant with the OMG ‘Extensible and Dynamic Topic Types for DDS’ specification, version 1.4), or leave it unset (the default setting) to be compliant with the specification (but not communicate with the Python API in previous releases).

For example, to communicate with the Python API in previous releases, you could set the Extensible Types compliance mask like this:

import rti.connextdds.compliance as compliance
compliance.set_xtypes_mask(
    compliance.get_xtypes_mask() | compliance.XTypesMask.PYTHON_INT8_730_BIT)

See Extensible Types Compliance Mask in the RTI Connext Core Libraries Extensible Types Guide for more information.

Note

This fix was also made in release 7.3.1; however, in that release, this bit was set by default, to communicate with releases that don’t have the fix (and therefore not break backward compatibility). In 7.7.0, this bit is unset by default to be compliant with the specification (and break backward compatibility by default).

If you want to communicate with Python APIs regardless of whether they have the fix, and/or communicate with all the bindings, a workaround is to not propagate the TypeObject and rely on the topic name for matching:

<domain_participant_qos>
    <resource_limits>
        <type_object_max_serialized_length>0</type_object_max_serialized_length>
    </resource_limits>
</domain_participant_qos>

If the application you’re communicating with uses a version of Connext earlier than 6.0.0, the TypeCode also needs to be configured to not be propagated:

<domain_participant_qos>
    <resource_limits>
        <type_code_max_serialized_length>0</type_code_max_serialized_length>
        <type_object_max_serialized_length>0</type_object_max_serialized_length>
    </resource_limits>
</domain_participant_qos>

See DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) in the Connext Core Libraries User’s Manual for more information on the type_code_max_serialized_length and type_object_max_serialized_length fields.

See Type Representation in the Connext Core Libraries Extensible Types Guide for more information on TypeCode and TypeObjects in current and previous releases.

3.1.2.3. Union discriminator initialization change

In previous releases, union discriminators were initialized to the default case if there was a default case or to the lowest value associated with any member if the union didn’t have a default case. However, this behavior was not compliant with the OMG ‘Extensible and Dynamic Topic Types for DDS’ specification, version 1.4.

In 7.7.0, union discriminators are now initialized to the default value of their type, as mandated by the specification. For unions based on enums, the discriminator will be initialized to the first literal defined in the enum.

This change may result in a union being constructed with a discriminator value that does not select any member. This is expected behavior under the compliance rules, but can affect existing applications that rely on the old initialization behavior.

If you wish to restore the previous behavior, modify the Extensible Types compliance mask by unsetting the initialize_discriminator_to_default() bit (0x00000100 sets the bit, 0x00000000 unsets it; the bit is set by default, making it compatible with the specification). You also need to regenerate code with Code Generator, using the flag -xTypesComplianceMask with the same mask.

For example, to restore the previous behavior, you could set the mask in modern C++ like this:

using namespace rti::config::compliance;
set_xtypes_mask(
            get_xtypes_mask() & ~XTypesMask::initialize_discriminator_to_default());

Or in Python, like this:

import rti.connextdds.compliance as compliance
mask = compliance.XTypesMask.INITIALIZE_DISCRIMINATOR_TO_DEFAULT_BIT
compliance.set_xtypes_mask(
    compliance.get_xtypes_mask() & mask.flip())

For more information, see Extensible Types Compliance Mask in the RTI Connext Core Libraries Extensible Types Guide.

Note

This fix was also made in release 7.3.1; however, in that release, this bit was unset by default, to communicate with releases that don’t have the fix (and therefore not break backward compatibility). In 7.7.0, this bit is set by default to be compliant with the specification (and break backward compatibility by default).

3.1.2.4. Recursive Type Support

While the TypeObject v2 specification [1] includes the structural framework to represent recursive types—types that contain members of their own type—Connext does not support recursive types out-of-the-box in this release.

If your system currently relies on recursive types, you must use TypeObject v1. You can do this by setting the DomainParticipantResourceLimitsQosPolicy::type_object_max_serialized_length in your Connext 7.7.0 application to a value large enough for your types and removing the TYPE_LOOKUP_SERVICE_CHANNEL from the DiscoveryConfigQosPolicy::enabled_builtin_endpoints mask.

<domain_participant_qos>
    <resource_limits>
        <type_object_max_serialized_length>8192</type_object_max_serialized_length>
    </resource_limits>
    <discovery_config>
        <enabled_builtin_channels>SERVICE_REQUEST_CHANNEL</enabled_builtin_channels>
    </discovery_config>
</domain_participant_qos>

3.1.2.5. TypeObject v1 no longer propagated by default

To optimize network performance, Connext no longer sends the TypeObject v1 representation by default. Connext can, however, receive TypeObject v1 by default. This is a significant shift for systems involving older Connext applications or those using DynamicData. Because older versions only understand TypeObject v1, they will not receive type definitions from newer applications, which effectively disables their ability to perform assignability checking. The older applications will match with the new applications based on type name only, and if the types are not assignable there is a risk for deserialization errors in the old application. Similarly, older DynamicData applications will lack the type information necessary to function.

To restore the previous behavior for backward compatibility, you must enable sending TypeObject v1 in your 7.7.0 application. You can do this by setting the DomainParticipantResourceLimitsQosPolicy::type_object_max_serialized_length to a value large enough for your types and removing the TYPE_LOOKUP_SERVICE_CHANNEL from the DiscoveryConfigQosPolicy::enabled_builtin_endpoints mask.

<domain_participant_qos>
    <resource_limits>
        <type_object_max_serialized_length>8192</type_object_max_serialized_length>
    </resource_limits>
    <discovery_config>
        <enabled_builtin_channels>SERVICE_REQUEST_CHANNEL</enabled_builtin_channels>
    </discovery_config>
</domain_participant_qos>

Alternatively, you can keep the TYPE_LOOKUP_SERVICE_CHANNEL enabled while also enabling TypeObject v1 propagation. This configuration allows your application to be backwards compatible with Connext versions prior to 7.7.0 and maintains the ability to respond to and make TypeLookup Service requests from systems that do not support TypeObject v1, such as those from other DDS vendors or your own applications where TypeObject v1 propagation is disabled.

To propagate TypeObject v1 and TypeObject v2:

  • Change type_object_max_serialized_length from 0 to the desired length.

  • Set the DiscoveryConfigQosPolicy::enabled_builtin_channels mask to include the TYPE_LOOKUP_SERVICE_CHANNEL.

See Type Representation in the RTI Connext Core Libraries Extensible Types Guide for more information.

Applications that enable both TypeObject v1 and the TYPE_LOOKUP_SERVICE_CHANNEL will not fully benefit from performance and feature improvements that were introduced with the addition of TypeObject v2 and the TypeLookup Service; however, enabling both provides a path towards full adoption of TypeObject v2 as your system migrates Connext versions.

3.1.2.6. Multiple Calls to Builtin Listeners

The introduction of the TypeLookup Service means that type resolution is now an asynchronous process. Consequently, the builtin PublicationBuiltinTopicData and SubscriptionBuiltinTopicData listeners on_data_available may be triggered multiple times for the same endpoint. The first call occurs when the endpoint is discovered but before the type definition has been retrieved; in this instance, the type_code will be NULL. A second call will occur once the type is successfully resolved. Any application logic that inspects discovered types must be updated to check for a non-NULL type_code before attempting to access it, to prevent runtime crashes.

3.1.2.7. Requirement for request_types_filter

Applications that need to discover types at runtime, such as those using DynamicData, must now take an active role in the discovery process. This is because Connext does not request types for endpoints for which it does not have a local endpoint match. This means that if a remote endpoint is discovered with a type hash that the local participant does not recognize, it will only request the type if there is a local endpoint for the same Topic as the remote endpoint and the QoS of the two endpoints otherwise match. That is, if they are on different partitions or have some other QoS incompatibility, the type will not be requested.

If your application requires discovering all types, either because you are using the discovered types to create DynamicData endpoints or using them for some other purpose, you can configure the DiscoveryConfigQosPolicy::request_types_filter. (See DISCOVERY_CONFIG QosPolicy (DDS Extension) in the RTI Connext Core Libraries User’s Manual.) The request_types_filter is a regular expression telling the participant which Topics it should unconditionally request the unknown types for. For example, if you want to request all unknown types, you can set it to *, and if you want to request types only for Topic “Foo”, you can set it to Foo.

Connext Infrastructure Services and Tools that rely on discovering types set this QoS to * by default. This could mean that they request more types than are necessary in your system. For example, in Routing Service, if you are only routing a subset of Topics, you may want to set request_types_filter to only request types for the Topics that you plan on routing.

3.1.3. Transport Compatibility

3.1.3.1. Real-Time WAN Transport updated message_size_max value may cause messages to be dropped from previous versions

The message_size_max for the RTI Real-Time WAN Transport has been decreased from 65535 to 1400 to avoid issues related to IP fragmentation that are common in WAN environments. (See What’s New in 7.4.0 in the RTI Real-Time WAN Transport Release Notes.) Because of this change, RTPS messages with serialized sizes larger than 1400 bytes may be dropped by the current release and the following error message will appear when two DomainParticipants discover each other:

ERROR [PARSE MESSAGE|0x01015772,0xEFEA70AC,0xB9D66813:0x000100C7{Entity=DR,MessageKind=DATA}|
RECEIVE FROM 0x0101C23E,0x7B2BF1E0,0xA1CDCA5F:0x000100C2|:0x000001C1{Domain=0}|ASSERT REMOTE DP|
LC:Discovery] PRESParticipant_checkTransportInfoMatching:INVALID CONFIGURATION |
the message_size_max, 65507, for udpv4_wan, of the remote participant (guid: 0x0101C23E,
0x7B2BF1E0,0xA1CDCA5F, name: '<UNKNOWN>'), does not match the message_size_max, 1400, of the local
participant (guid: 0x01015772,0xEFEA70AC,0xB9D66813, name: '<UNKNOWN>'). Will lose RTPS packets
with size > 1400.

The messages are dropped because the DDS_ReceiverPoolQosPolicy::buffer_size default value is set to an AUTO value that takes the maximum value of the message_size_max across all installed transports in a DomainParticipant. Because it is a maximum across all installed transports, if you have another transport installed (such as the builtin shared memory or UDPv4 transports) and have not changed the message_size_max for those transports, then you will not have a problem with dropped messages, even if you see the error message about dropped packets for the UDPv4_WAN transport.

You can avoid dropped messages by doing one of the following:

  • Update the message_size_max in versions before 7.4.0 to 1400. You can use the BuiltinQosSnippetLib::Transport.UDP.WAN snippet. This QoS snippet enables the Real-Time WAN Transport, sets the message_size_max to 1400, and enables asynchronous publishing, which was required in previous releases to support data fragmentation when using reliable communication (that requirement has been removed in this release). For example:

    <qos_profile name=”MyProfile”>
        <base_name>
            <element>BuiltinQosSnippetLib::Transport.UDP.WAN</element>
        </base_name>
    ....
    </qos_profile>
    
  • Change the value of the DDS_ReceiverPoolQosPolicy::buffer_size QoS to be as large as the message_size_max of the application running a previous version of Connext (65535 if it was left to the default). For example:

    <qos_profile name=”MyProfile”>
        <domain_participant_qos>
            <receiver_pool>
                <buffer_size>65535</buffer_size>
            </receiver_pool>
    ....
        </domain_participant_qos>
    ....
    </qos_profile>
    
  • Update the message_size_max in 7.7.0 to be the same as the previous version (65535 if it was previously left untouched). For example:

    <qos_profile name=”MyProfile”>
        <domain_participant_qos>
            <transport_builtin>
                <udpv4_wan>
                <message_size_max>65535</message_size_max>
                </udpv4_wan>
            </transport_builtin>
    ....
        </domain_participant_qos>
    ....
    </qos_profile>
    

    This solution has the disadvantage that you are likely to run into issues related to IP fragmentation. For more information about IP fragmentation and DDS fragmentation, see Disabling IP Fragmentation for Real-Time WAN Transport in the RTI Connext Core Libraries User’s Manual.

Footnotes