.. include:: vars.rst
.. _section-routingData:
********************************************
Routing Data: Connecting and Scaling Systems
********************************************
This chapter is devoted to present the most elemental function of |RS|: routing
data across multiple DDS domains. Routing data refers to the process of propagating
the |Topic| user data from domain to another, allowing systems to interconnect
and scale.
:numref:`FigureRouterBasicInoutBox` shows the most basic view of the |RS| model. You
can think of it as a black box composed of multiple *Input* |DRs| and *Output* |DWs|,
each associated with a specific |TOPIC|. Data flows from the input |DRs| to the output
|DWs|. The input |DRs| receive data from the *publication side*, whereas the output
|DWs| send data to the *subscription side*.
.. figure:: static/RouterBasicInoutBox.svg
:figwidth: 90 %
:name: FigureRouterBasicInoutBox
:align: center
Basic model of |RS|
The |RS| engine takes the data from an input |DR| and passes it along to a specific
output |DW|, as if there was a link connecting input and output. This activity
is known as the *forwarding process*. |RS| allows configuring this forwarding
process.
The following sections will guide you through all the |RS| entities involved in
the forwarding process and how they are configured.
.. note::
All the following sections assume you are already familiar with basic DDS
concepts. Additionally you should be familiar with the *RTI* |SHAPESDEMO| tool.
Refer to :ref:`section-Tutorials` if you need more information.
.. _section-routingData-SingleTopic:
Routing a |TOPIC| between two different domains
===============================================
The most basic use case of |RS| is about forwarding the data for a specific |TOPIC|
from one domain to another. This process is known as *routing a* |TOPIC|.
:numref:`FigureRouterBasicTwoTopics` illustrates this concept.
.. figure:: static/RouterBasicTwoTopics.svg
:figwidth: 90 %
:name: FigureRouterBasicTwoTopics
:align: center
Basic |TOPIC| routing among domains for a |TOPIC| with name Squares
The samples for the |TOPIC| named ``Square`` in domain 0 are forwarded to
the same |TOPIC| but in domain 1. You will first run
:ref:`section-Tutorials-ExampleSingleTopic` in your machine to see the
functionality in action. Then we will break down all the parts related to |RS|.
Let's review step-by-step each element that appears in the |RS| XML configuration,
understanding its purpose and what each of its entities is modeling.
Define the service configuration element
----------------------------------------
The first step is to define the top-level element for the |RS| configuration:
.. code-block:: xml
...
This element defines a configuration profile for |RS|. It must appear within
the tag ````–the root tag for all the elements related to |CONNEXT|–. The
configuration shall contain a ``name`` attribute that uniquely identifies the
service, and determines the *service configuration name*. You can define
multiple service configurations in one XML file, and **select one to instantiate
a** |RS| by providing the configurations name with the ``-cfgName`` option (or
``ServiceProperty::cfg_name`` member when using the Service API).
As we'll see further below, the ``name`` attribute is an important concept since
it establishes the *configuration name* of a |RS| entity. This name can be used
from other elements in the configuration to refer to a specific entity.
.. seealso::
:ref:`section-Usage`
How to run |RS| using the shipped executable or embeddeding it into your
application with the Service API.
:ref:`section-config-routing-service`
Reference for the XML configuration of the service element.
Specify which domains to join
-----------------------------
Within the top-level |RS| configuration we need to specify which *domains* |RS| will
be joining. The specification of the domains occurs within the |DOMAINROUTE|, which
represents a *mapping* between multiple DDS domains through a collection of |DPs|.
In our example, we are joining domains 0 and 1 and we relay on the default
participant QoS settings, so the XML looks as follows:
.. code-block:: xml
01
...
You can specify as many |DPs| as needed. An important aspect to pay attention is
the **configuration name assigned to each participant**. This name is what
uniquely identifies a domain and is referenced later by |INPUTs| and |OUTPUTs|
to indicate the |DP| from which the |DR| and |DW| are created, respectively.
.. note::
The value specified with ``>`` in the XML participant configuration
can be offset with the ``-domainIdBase`` command-line option. The participant
will be created with domain ID = ```` + ``-domainIdBase``.
In addition, the ``name`` attribute of the participant configuration is used
to form the name assigned to the actual |DP| by setting the
:link_connext_users_man_s:`EntityName QoS `.
.. seealso::
:numref:`TableParticipantTag` in :ref:`section-Config-DomainRoute`
How |RS| constructs the name assigned to the |DP|.
:numref:`FigureRouterDomainRouteResource` shows the |DOMAINROUTE| resource model,
denoting the association with the service and participant entities.
.. figure:: static/RouterDomainRouteResource.svg
:figwidth: 90 %
:name: FigureRouterDomainRouteResource
:align: center
|DOMAINROUTE| resource model
Define a processing context
---------------------------
One of the main aspects that contributes to the high performance of |RS| is the
ability to parallelize the processing of the data streams. You can create
*threading contexts* to execute of all the activities related to the processing of
the data streams. A threading context involves **one or more threads**–a thread pool–,
and is specified by the |SESSION| entity.
In our example we define a single |SESSION| to take care of processing the data for
the single |TOPIC| that is forwarded:
.. code-block:: xml
...
The |SESSION| must appear inside the |DOMAINROUTE| and you can specify as many
|SESSIONs| as you want. In our configuration we rely on the default values, which
define a single-threaded context. You could specify a thread pool if, for example,
you wanted to parallelize the forwarding of multiple |TOPICs|.
:numref:`FigureRouterSessionResource` shows the |SESSION| resource model.
.. figure:: static/RouterSessionResource.svg
:figwidth: 90 %
:name: FigureRouterSessionResource
:align: center
|SESSION| resource model
.. seealso::
Session configuration in :ref:`section-config-session`
Reference for the XML configuration of the |SESSION| element.
Define the data flow
--------------------
The last step consists of defining the flow of *data streams*. For the |TOPIC|
*routing* use case, we need to indicate that the **data from a** *Topic* **in the
publication side shall be routed to the same topic in the subscription side**.
The |TR| is the entity that allows you to define these data flows for the
forwarded data.
A |TR| is a data processing unit composed of the DDS |INPUTs| and |OUTPUTS| that
receive and send the data, respectively. Hence a |TR| effectively represents the
establishment of a *route* that data streams follow. Data from the publication side
is forwarded to the subscription side.
In our example we just define a |TR| with a single |INPUT|–containing a |DR|–
and a single |OUTPUT|–containing |DW|–.
.. code-block:: xml
SquareShapeType
Notice how the |INPUT| and |OUTPUT| are *attached* to a concrete |DP| using the
the ``participant`` attribute. The value of this attribute is the name of one
the participant configurations defined in the parent |DOMAINROUTE|. This is how
you indicate to which domain the |INPUT| and |OUTPUT| are connected to–or from
which |DP| the |DR| and |DW| are created, respectively–.
In our example, the |INPUT| is attached to the participant configuration with name
``domain0`` for domain 0, whereas the |OUTPUT| is attached to ``domain1`` for domain 1.
Additionally, for each |INPUT| and |OUTPUT| we need to specify at least two
elements:
- **Name of their associated** *Topic*. This indicates the name of the topic
for which the |DR| and |DW| are created. In this example, both entities are
created from the ``Square`` topic.
- **Registered name of the type** associated with the |TOPIC|. This is the name
used to identify the type of the user-data samples that are read and written
by the input |DR| and output |DW|. |RS| needs to obtain the information prior
to create the |DR| and |DW|. There are two provide the type information:
- Manually by defining the type in XML
- Through discovery from any of the |DP| within the parent |DOMAINROUTE|.
This is the mechanism our example relies to get the type and in this case
the type is identified by the registered name ``ShapeType`` (you can
find the the definition of this type in ``[NDDSHOME]/resource/idl/ShapeType.idl``)
You can learn more about type registration and how to configure it in
:ref:`section-Config-StreamPort-Types`.
For this case of routing a |TOPIC|, both the **input and output topic its
associated type are the same**. This is often the situation when you want to
simply route data across domains for system integration and scalability.
Nevertheless, |RS| is flexible to allow using different topics and types. In
that case you will need to *plug* custom code to perform the routing.
:ref:`section-controllingData` addresses this use case.
:numref:`FigureRouterRouteResource` shows the |TR| resource model.
.. figure:: static/RouterRouteResource.svg
:figwidth: 90 %
:name: FigureRouterRouteResource
:align: center
|TR| resource model
.. seealso::
|TR| configuration in :ref:`section-Config-Route`
Reference for the XML configuration of the |TR| element.
.. _section-routingData-TopicGroup:
Routing a group of |TOPICs|
===========================
In section :ref:`section-routingData-SingleTopic` we learned how to route a
specific |TOPIC|. We showed how to create a dedicated |TR| to forward the data for a
concrete |TOPIC|. You can replicate this process for each |TOPIC| you want to route.
However, this process may become repetitive and in some cases avoidable. When
such is the case, you can use the |ATR| to **automate the routing for a group of**
|TOPICs|. An |ATR| allows you to specify a set of *potential* |TRs| that |RS|
will create on-demand upon dynamic *discovery* of the |TOPIC| to be routed.
:numref:`FigureRouterBasicAutoRouteConcept` shows the concept of the |ATR|. An
|ATR| specifies a *regular expression* that is applied upon the discovery of any
new |TOPIC|. The |ATR| creates a new |TR| for each newly discovered |TOPIC| whose
name matches with the |ATR|'s expression.
.. figure:: static/RouterBasicAutoRouteConcept.svg
:figwidth: 90 %
:name: FigureRouterBasicAutoRouteConcept
:align: center
|ATR| concept
An |ATR| allows defining a set of potential |TRs| that have a single |INPUT|
and a single |OUTPUT|, both tied to their corresponding domain. A regular
expression can be specified separately for publication and subscription
|TOPICs|. Hence, when the |ATR| matches either with a publication or
subscription |TOPIC|, it will create a |TR| to route the matched |TOPIC|.
Let's first run :ref:`section-Tutorials-ExampleAllTopics` to see this functionality.
This example shows how to configure a |RS| to route *all* the |TOPICs| from domain
0 to domain 1 using an |ATR|. To accomplish that, we have defined the |ATR| as follows:
.. code-block:: xml
true**rti/*
The configuration of the |ATR| is such that matches the name and registered type
name of every |TOPIC| on either ``domain1`` or ``domain2``, *except* the |TOPICs|
whose name starts with ``rti/``.
An |ATR| allows you to specify two sets of regular expressions for both the
input and output of the potential |TRs|:
- ``allow_topic_name_filter`` and ``allow_registered_type_name_filter`` specify
the set of |TOPIC| names and types that are accepted for the dynamic creation
of |TRs|. If **both expressions evaluate as true**, a new |TR| will be created,
unless one of the deny filter evaluates as true.
- ``deny_topic_name_filter`` and ``deny_registered_type_name_filter`` specify
the set of |TOPIC| names and types for which the creation of |TRs| is denied.
If **any of the expressions evaluate as true**, the creation of the |TR| will
be rejected. These expressions are evaluated after the allow filters, and only
if these evaluated as true.
The configuration for the input and output of the |ATR| can contain a |DR| and
|DW| QoS respectively. You can leverage the concept of **QoS topic filters** to
use a different QoS profile based on the name of the matched |TOPIC| (See
:ref:`section-routingData-CustomQos-topicFilters`).
You can also observe from the example that the |ATR| is defined under a |SESSION|.
This means that all the created |TRs| will run under that context.
:numref:`FigureRouterAutoRouteResource` shows the |ATR| resource model.
.. figure:: static/RouterAutoRouteResource.svg
:figwidth: 90 %
:name: FigureRouterAutoRouteResource
:align: center
|ATR| resource model
.. seealso::
|TR| configuration in :ref:`section-Config-AutoRoute`
Reference for the XML configuration of the |ATR| element.
.. _section-routingData-CustomQos:
Using custom QoS Profiles
=========================
In the previous sections, we showed scenarios in which all the DDS entities of |RS|
are created with default QoS. That is, all the QoS policies are set with the initial
default values as specified in the |CONNEXT| documentation
(see :link_qos_cheatsheet:`QoS Reference Guide <>`).
For the majority of the cases though, you may want to specify your custom QoS values
for the DDS entities of |RS|. You can easily do that in XML by defining your
QoS Profiles and **inherit from them** when specifying the configuration of
QoS for each DDS entity.
Let's take a look to each step individually.
Defining a QoS Library
----------------------
You can define XML QoS profiles for |RS| the same way you can do it for a regular
|CONNEXT| application. You can define QoS libraries containing profiles directly
under the ```` root element. For example:
.. code-block:: xml
...
...
...
...
...
As we will see shortly in the next step, within the |RS| configuration you can
reference these profiles in order to configure the corresponding underlying
DDS entities.
You can define as many QoS libraries as you want, each with multiple profiles.
Additionally, the definition of QoS libraries can appear either in the same file that
contains the |RS| configuration or in a separate one. For information on how
to configure QoS in XML, see
:link_configuring_qos_xml:`Configuring QoS with XML in the RTI Connext User's Manual<>`.
.. seealso::
Loading XML configurations in :ref:`section-Common-Config`
How lo load XML configurations in |RS|.
Specifying QoS for DDS entities
-------------------------------
You can configure the QoS for each DDS entity that |RS| creates. To accomplish this,
each |RS| entity that creates an underlying DDS entity provides a corresponding
tag to specify its QoS.
For example, to configure the QoS for the |DPs| of a |DOMAINROUTE|, you can specify
a ```` tag as follows:
.. code-block:: xml
...
...
...
The QoS tag can have a ``base_name`` attribute to inherit from any available QoS
profile, including :link_connext_builtin_qos:`builtin QoS profiles <>`. Additionally,
inline values for QoS policies can be specified in order to override default values
or set by the base profile.
:numref:`TableCustomQosEntityTags` shows the a list of |RS| entities and the DDS
entities they create, along with the tags that configure them.
.. list-table:: Configuration of the |RS|'s underlying DDS entities.
:name: TableCustomQosEntityTags
:widths: 20 20 60
:header-rows: 1
:class: longtable
* - |RS| Entity
- DDS Entity
- QoS tag
* - |DOMAINROUTE|
- |DP|
- ````
Example:
.. code-block:: xml
* - |SESSION|
- |PUB|
- ````
Example:
.. code-block:: xml
* -
- |SUB|
- ````
Example:
.. code-block:: xml
* - |TR|'s |INPUT| or
|ATR|'s |INPUT|
- |DR|
- ````
Example:
.. code-block:: xml
* - |TR|'s |OUTPUT| or
|ATR|'s |OUTPUT|
- |DW|
- ````
Example:
.. code-block:: xml