Understanding Instance States
Note: This article is based on the 6.1.0 release of RTI Connext DDS.
This article explains what Instances and Instance States are, describes how they apply whether you use them or not, and clears up some common misconceptions.
Instances
An Instance is defined as representing a unique object within a Topic, identified by unique values of key fields. Instances are useful if your data model describes individual real-world objects; Instances represent these individual objects on a DDS level. Take the following IDL data type, for example:
struct VehicleData { @key int32 vehichleId; float velocity; // ... Additional information };
Here the data type has a single key field, vehicleId
, which forms a Key, meaning that all data samples that share a vehicleId
represent the same vehicle. In more generic terms, all data samples that have the same Key represent the same Instance.
Many QoS settings and APIs work on a per-Instance basis allowing you to, for example, set the maximum history depth per-Instance instead of per-Topic, or read the latest sample from a given Instance. In our vehicle example above, this means that we can easily keep track of the latest velocity of each individual vehicle -- if the history QoS worked per-Topic we would only have the most recent velocity published for a single vehicle.
However, defining key fields for a data type is not mandatory and, depending on your data model, may not be necessary. In this case, all data for a given Topic will be treated as if it belongs to a single Instance.The RTI Connext DDS Getting Started Guide has some useful overview information about Instances in Introduction to Keys and Instances.
Instance States
There are three possible Instance States that are defined by the OMG DDS Standard: ALIVE, NOT_ALIVE_DISPOSED, and NOT_ALIVE_NO_WRITERS.
An Instance will enter the ALIVE state upon being written to by a DataWriter, and will enter one of the two NOT_ALIVE_ states if it is no longer expecting to be written to. An Instance will transition to NOT_ALIVE_DISPOSED if one DataWriter disposes of the Instance (*see the note in ‘Mistakes and Pitfalls’ below regarding ownership QoS). An Instance will transition to NOT_ALIVE_NO_WRITERS if all DataWriters that have written to that Instance unregister from it or lose liveliness.
The following diagram shows how RTI Connext DDS handles the different possible transitions between Instance States, in accordance with the definitions provided by the standard:
Note that there are various QoS settings that modify this behavior, some of which were enabled by default in previous versions of RTI Connext DDS. Some of these are mentioned in the next section of this article.
As one might expect, Instance States are useful for determining the state of a real-world object that an Instance represents. Without Instance States, you would have to track these states at the application level. While the semantic meaning of dispose varies from system to system, it generally indicates that an object/Instance no longer exists for the purposes of a system. An unregister or loss of liveliness means that an object/Instance will not be updated by a given DataWriter.
If we take the previous VehicleData
data type example and assume that it is being used to track cars in a car park, then an Instance entering the NOT_ALIVE_DISPOSED state could indicate that the Instance (a specific car) has been detected leaving the car park and thus no longer exists within the context of the system. An Instance in the NOT_ALIVE_NO_WRITERS state means that there are no sensors currently responsible for updating information regarding that vehicle.
Mistakes and Pitfalls
When manually unregistering Instances, a common pitfall is that, in versions of RTI Connext DDS prior to 6.1.0, the autodispose_unregistered_instances
QoS is set to true by default. This means that a call to unregister_instance()
also implicitly calls dispose()
, meaning that unregistering an Instance, either manually or implicitly by deleting a DataWriter, will set the Instance State to NOT_ALIVE_DISPOSED instead of the expected value of NOT_ALIVE_NO_WRITERS.
Other QoS settings, while not enabled by default, can also modify the behavior of Instance State transitions in a way that may not be immediately obvious. Some of these include:
propagate_dispose_of_unregistered_instances
: When set to true, allows transitions from NOT_ALIVE_NO_WRITERS to NOT_ALIVE_DISPOSED, or allows the initial state to be NOT_ALIVE_DISPOSED.propagate_unregister_of_disposed_instances
: When set to true, allows transitions from NOT_ALIVE_DISPOSED to NOT_ALIVE_NO_WRITERS.ownership
: If set to EXCLUSIVE, only the DataWriter with the highest ownership_strength can dispose an Instance and thus transition to the NOT_ALIVE_DISPOSED state.
A full list of QoS settings that affect instances can be found in QoS Configuration and Instances in the Core Libraries User’s Manual.
Finally, another common misunderstanding is conflating Instance State with a DataWriter’s liveliness, especially when using unkeyed data where there may be a one-to-one relationship between an Instance and a DataWriter. An Instance will only enter the ALIVE state if it is written to, whereas a DataWriter simply has to assert liveliness, meaning that a DataWriter could gain liveliness while the Instance is in the NOT_ALIVE_NO_WRITERS state. The correct way to check a DataWriter’s liveliness is to listen for the LIVELINESS_CHANGED DataReader status.
This has been a quick overview with basic information regarding the use of Instances. Some details, such as the impact of Instances on memory or information on the APIs that can be used with Instances, have been omitted for the sake of simplicity. For a more in-depth guide to Instances, see the following sections of the Core Libraries User's Manual:
- Working with Instances (a more detailed overview of Instances)
- Managing Instances (from the DataWriter perspective)
- Accessing and Managing Instances (from the DataReader perspective)