What QoS policies do I need to change when creating a reliable reader and writer?

This Solution addresses how to create a reader and a writer that use reliable communication. It also shows, by example, some of the more common QoS policies that you might want to change.

Method One for modifying the QoS

The following C++ code snippet shows how to change those QoS policies.

Data Reader

DDS_DataReaderQos reader_qos;
/* Customize data reader QoS to create reliable data reader and control reliability */ 

retcode = subscriber->get_default_datareader_qos(reader_qos); 
if (retcode != DDS_RETCODE_OK) { 
    printf("get_reader_qos error %d\n", retcode); 
    subscriber_shutdown(participant, subscriber, topic, reader); 
    return -1; 
} 

/* make the reader reliable */
reader_qos.reliability.kind = DDS_RELIABLE_RELIABILITY_QOS;

/* This is not required for reliable communication. 
 * It's only useful if you need late -joining reader to get 
 * previous data */
reader_qos.durabiliy.kind = DDS_TRANSIENT_LOCAL_DURABILITY_QOS; 

Note: It’s optional but highly recommended to set the receive-queue size on the subscriber side. This gives the receiver some buffer in which to keep issues, in case issues arrive out of order. This will help the efficiency of your program.

For absolute reliability, set reader_qos.history.kind to DDS_KEEP_ALL_HISTORY_QOS. This will cause RTI Connext to keep as much unacknowledged data in the history as possible, until it runs out of system resources. In the case of TRANSIENT_LOCAL_DURABILITY, RTI Connext will attempt to keep all past issues until it hits the system resource 
limits.

DDS_KEEP_LAST_HISTORY_QOS allows old messages to be overwritten, even if the message hasn't been acknowledged or read. This would only occur if you tried to publish data when the send queue is full and the specified wait period for an empty slot in the queue has passed.

/* samples that should be maintained until they are taken */
reader_qos.history.kind = DDS_KEEP_LAST_HISTORY_QOS;
reader_qos.history.depth = 5;

 /* create the reader, using the modified QoS */
reader = subscriber->create_datareader(topic, reader_qos, 
                                       reader_listener,
                                       DDS_STATUS_MASK_ALL);
if (reader == NULL) {
     printf("create_datareader error\n");
     subscriber_shutdown(participant,subscriber, topic, reader);
     delete reader_listener;
     return -1;
}
DDS_DataWriterQos writer_qos;
/* Customize data writer QoS to control reliability */
retcode = publisher->get_default_datawriter_qos(writer_qos);
if (retcode != DDS_RETCODE_OK) {
    printf("get_writer_qos error %d\n", retcode);
    publisher_shutdown(participant, publisher, topic, writer);
    return -1;
}
 
/* By default, DataWriter is RELIABLE with a history depth of 1.
 * It's optional to set the blocking time on a send, which is the
 * maximum time to block if data writer does not have space to
 * store the value written. For example, to set it to 2 seconds: 
 */
blocking_time.sec = 2;
blocking_time.nanosec = 0;
writer_qos.reliability.max_blocking_time = blocking_time;
 
/* This is not required for reliable communication.  It's only
 * useful if you need late-joining reader to get previous data. 
 */
writer_qos.durability.kind = DDS_TRANSIENT_LOCAL_DURABILITY_QOS;

/* samples that should be maintained by the DataReader on behalf
 * of existing data reader 
 */
writer_qos.history.kind = DDS_KEEP_LAST_HISTORY_QOS;
writer_qos.history.depth = 5;
 
/* Note: For absolute reliability, set writer_qos.history.kind 
 * to DDS_KEEP_ALL_HISTORY_QOS. 
 * create the writer, using the modified QoS. */
writer = publisher->create_datawriter(topic, writer_qos, 
                                      NULL /* listener */,
                                      DDS_STATUS_MASK_NONE);
if (writer == NULL) {
    printf("create_datawriter error\n");
    publisher_shutdown(participant, publisher, topic, writer);
    return -1;
 }       

Method Two for modifying the QoS (applies to version 4.3 and higher)

This method uses an XML QoS profile to configure the DomainParticipant and transport properties.

<dds>
  <qos_library name="DefaultLibrary"> 
    <qos_profile name="Reliable" is_default_qos="true">
      <datareader_qos>
        <reliability>
          <kind>RELIABLE_RELIABILITY_QOS</kind>
        </reliability>
        <history>
          <kind>KEEP_LAST_HISTORY_QOS</kind>
          <depth>5</depth>
        </history>
        <durability>
          <kind>TRANSIENT_LOCAL_DURABILITY_QOS</kind>
        </durability>
      </datareader_qos>
      <datawriter_qos>
        <reliability>
          <kind>RELIABLE_RELIABILITY_QOS</kind>
          <max_blocking_time>
            <sec>2</sec>
            <nanosec>0</nanosec>
          </max_blocking_time>
        </reliability> 
        <history> 
          <kind>KEEP_LAST_HISTORY_QOS</kind> 
          <depth>5</depth> 
        </history> 
        <durability> 
          <kind>TRANSIENT_LOCAL_DURABILITY_QOS</kind> 
        </durability> 
      </datawriter_qos> 
    </qos_profile> 
  </qos_library> 
</dds> 

If you are using RTI Data Distribution Service 4.3e, you must call DDSTheParticipantFactory->load_profiles() before creating the DomainParticipant with a profile.

When using RTI Data Distribution Service 4.4 and higher, the XML file can be automatically loaded. If NDDS_QOS_PROFILES.xml is in the $NDDSHOME/resource/xml directory, it will be automatically loaded. Similarly, if USER_QOS_PROFILES.xml is in the working directory, it will be automatically loaded. See the Core Libraries and Utilities User’s Manual for more details on XML file loading.

When using version RTI Data Distribution Service 4.4 and higher, place the attached USER_QOS_PROFILES.xml file in the working directory. It specifies "DefaultLibrary" as the default QoS profile and will be loaded when your RTI Connext application starts.

Testing To demonstrate the reliability behavior

  1. Start the publisher and wait for it to start publishing
  2. Start two subscribers
    Note: It is possible for the subscribers to miss the first couple of issues because they were not yet discovered by the publisher when those issues were sent, so the publisher discards the data. To avoid this situation, set the durability to TRANSIENT_LOCAL so that late-joining  subscribers will get previous data.
  3. Stop one of the subscribers and wait until the publisher has issued at least 5 issues.
  4. Restart the subscriber.

The History QoS setting will cause the subscriber to get the last 5 published issues. If you waited longer than 5 published issues before restarting the publisher, issues older than 5 will not be received by the subscriber.