Leave Data in the Middleware Queue When Possible
You have two options for how to access data that a DataReader receives. The first option is to call take(), which removes data from the DataReader’s queue. The second option is to call read(), which leaves data in the middleware queue for later access.
Both of these options are reasonable, depending on your use case and the QoS settings you are using. If you are receiving data from the network that you are modifying or combining into a new object, you will generally want to remove the data from the middleware’s queue. However, if you are using the data as-is from the middleware queue and simply copying it into your own queue, you should consider leaving it in the middleware to save yourself from the overhead of copying the data.
However, you should be cautious about leaving data in the middleware queue, because the queue characteristics are controlled by QoS. These characteristics include:
- The maximum total number of samples in the queue (resource_limits.max_samples)
- The maximum total instances in the queue (resource_limits.max_instances)
- The maximum samples per instance in the queue (resource_limits.max_samples_per_instance)
- Whether the middleware is allowed to overwrite existing data in the queue if new data arrives, or whether it will store data until it hits the resource limits, and possibly reject data when the queue is full (history.kind)
Also note that RTI Connext DDS was designed for embedded systems, so it does not deallocate memory from the queue unless you delete the DataReader.
The most common use cases where people leave data in the middleware queue are:
- Polling for the state of all objects: State data is represented by using multiple instances, and using a history QoS set to KEEP_LAST with a depth of 1. This allows you to retrieve the current state of each instance, and to know that if the state is updated, it’s automatically overwritten in the queue.
- Querying the state of certain objects: This also assumes that you represent your data as state data by using keys, and your history QoS set to KEEP_LAST with a depth of 1. However, in this case you query for the state of an individual object or a group of objects by using a QueryCondition.
An example of using a query condition to query the current state of a particular object:
// Create a query condition that will be used later to access a specific // flight plan in the DataReader's queue. This is looking up the flight // plan based on the field ‘flightId’ DDS_StringSeq queryParameters; queryParameters.ensure_length(1,1); queryParameters[0] = DDS_String_dup("''"); _queryForFlights = _reader->create_querycondition(DDS_ANY_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ALIVE_INSTANCE_STATE, DDS_String_dup("flightId MATCH %0"), queryParameters); // later ... // Note that a QueryCondition requires that the single quotes around // a string are inside the query condition parameter, so this creates // a string with single-quotes around the flight ID. char flightName[10]; sprintf(flightName, "'%s'", flightId); // Adding ' ' around the char * queryParameters[0] = DDS_String_dup(flightId); _queryForFlights->set_query_parameters(queryParameters); // Use the QueryCondition to access the data in the DataReader FlightPlanSeq flightSeq; SampleInfoSeq infoSeq; _reader->read_w_condition(flightSeq, infoSeq, DDS_LENGTH_UNLIMITED, _queryForFlights); if (flightSeq.length() > 0) { // if this is state data (history = keep last, depth = 1), there // will only be a single data item if flightId is the key field. if (infoSeq[0].valid_data) { FlightPlanTypeSupport::copy_data(plan, &flightSeq[0]); } } _reader->return_loan(flightSeq, infoSeq);
A full example of polling and using QueryConditions to access a subset of the data in the DataReader’s queue is here:
http://community.rti.com/examples/polling-query-condition