Request/Reply patter for Modern C++

9 posts / 0 new
Last post
mpichini's picture
Offline
Last seen: 1 year 5 months ago
Joined: 09/16/2015
Posts: 27
Request/Reply patter for Modern C++

Hi there,

are you planning to make available the Request/Reply pattern implementation also for Modern C++ ?
In case is there any idea about when the implementation will be available ?

Personally I don't like the idea of mixing modern and traditional C++.

Best Regards

mpichini's picture
Offline
Last seen: 1 year 5 months ago
Joined: 09/16/2015
Posts: 27

There's also an additional problem that prevents the mixing of Modern C++ and Traditional C++ caused by the compilation of the idl files with rtiddsgen.

We compile for language C+11 (all our application is written to use c++ 2011 features) and therefore the generated C++ classes cannot be used in traditional C++ modules.

 

Offline
Last seen: 2 months 3 weeks ago
Joined: 04/02/2013
Posts: 196

Hi Massimo,

We plan to release the modern C++ request-reply API with our next major release, in 2017.

In the meantime, this solution may help you, although you may already have seen it: How do I use the Traditional C++ and Modern C++ APIs in the same application?

Unfortunately, if you want to publish and/or subscribe to the same types in both APIs, you will have to generate and compile the type plugin separately for each.

I hope this helps.

Alex

 

mpichini's picture
Offline
Last seen: 1 year 5 months ago
Joined: 09/16/2015
Posts: 27

Hi Alex,

we are currently using only few of the request-reply API features: basically a single requestor and a single replier. The replier can send back multiple responses to a requestor. Requestors/repliers may be written in C++ and java.

I guess that the implementation is not so complicated (considering this reduced use case) and I was wondering if there's any technical information available that will allow me to implement a simplified version of the request-reply API.

Basically I guess I would only need to understand how the correlation id is generated (the flag for the intermediate reply is already described in the Connext User Manual as well as how the topic names are generated from the service name).

Let me know if this is feasible or not

Thank you very much
Massimo

Offline
Last seen: 2 months 3 weeks ago
Joined: 04/02/2013
Posts: 196

As you said, the key element to the request-reply pattern is the correlation between replies and the request that originated them. 

The correlation process is as follows:

  • Requester DataWriter is identified by a specific GUID (let's call it requester_guid)
  • Requester DataWriter writes a request normally
  • Replier DataReader receives the request
  • Replier DataWriter writes a reply, using WriteParams::related_sample_identity().guid() set to request.info().original_publication_virtual_guid() (== requester_guid)
  • Requester DataReader has a ContentFilteredTopic that only allows samples such that original_publication_virtual_guid == requester_guid.*

* The following code generates the CFT expression you need:

const int GUID_SIZE = 16;
const char * GUID_FIELD_NAME = "@related_sample_identity.writer_guid.value";
void append_guid(std::ostringstream& os, const rti::core::Guid& guid)
{
 for (int i = 0; i < GUID_SIZE; i++) {
 if (guid[i] < 0x10) {
 os << "0";
 }
 os << std::hex << (int) guid[i];
 }
}
std::string create_correlation_filter_expression(
 const rti::core::Guid& correlation_guid)
{
 std::ostringstream expression;
 expression << GUID_FIELD_NAME << " = &hex(";
 append_guid(expression, correlation_guid);
 expression << ")";
 return expression.str();
}

This is enough to make sure the Requester only receives replies directed to it. This is not enough to allow sample-level correlation—that is, waiting for a reply to a specific request.

I hope this helps.

Alex

mpichini's picture
Offline
Last seen: 1 year 5 months ago
Joined: 09/16/2015
Posts: 27

Thank you very much Alex.

I think this should allow me to implement an intermin solution waiting for the next major release of RTI Connext DDS coming in 2017.

best regards
Massimo

mpichini's picture
Offline
Last seen: 1 year 5 months ago
Joined: 09/16/2015
Posts: 27

Hi Alex,

I'm testing the replier side written in Modern C++ using a Java client program as Requester.
I had to use the DataWriterImpl since I found no DataWriter write methods that accepts a WriteParams object as argument.

I got the following error from DDS when try to send back the reply to the requester:

[1467046337.956616] rR0100114ba01
  DDS_WriteParams_is_consistent:ERROR: Bad parameter: related_sample_identity
[1467046337.956634] rR0100114ba01
  DDS_DataWriter_write_w_params_untyped_generalI:ERROR: Bad parameter: params
[1467046337.957508] rR0100114ba01

This is the piece of code that initialize the WriteParams:

    rti::pub::WriteParams wp;
    rti::core::Guid guid(sampleInfo.delegate().original_publication_virtual_guid());
    rti::core::SampleIdentity si(guid, rti::core::SequenceNumber::automatic());
    wp.related_sample_identity(si);

 

I have no idea how to initialise the sequence number of the sample identity so I used an automatic value provided by RTI Connext.
I also how to initialize have no idea how to initialize any other WriteParams attribute.

I'm also wondering if there's any to be done on WriteParams on the Requester side of the application.

Could you please help ?
thank you very much for your kind support

Massimo

Offline
Last seen: 2 months 3 weeks ago
Joined: 04/02/2013
Posts: 196

Hi Massimo,

1) The write overload that receives WriteParams is an RTI extension, so the standard requires to access it with " ->"

writer->write(data, params);

2) Writing with related_sample_identity requires a concrete guid and a concrete sequence number. You can get both packed in a SampleIdentity instance:

SampleIdentity sample_id = sample_info->original_publication_virtual_sample_identity(); // note the use of "->" to access an extension
Offline
Last seen: 5 years 2 weeks ago
Joined: 08/25/2014
Posts: 7

Dear all,

following the descriptions above, I managed to create a CFT that filters samples according to a given GUID, so this is nice. However, I fail to create a QueryCondition that would allow me to use a WaitSet for a specific sample with a given "sequence_number". My naive approach is as follows:

std::string query_expression = "@related_sample_identity.sequence_number.value = " + std::to_string(sequence_number.value());
 
auto default_read_state = dds::sub::status::DataState();
default_read_state << dds::sub::status::SampleState::not_read();
 
dds::sub::cond::QueryCondition(dds::sub::Query(reader, query_expression), default_read_state);

When I execute this, I get the following error: 

[D0100|Reader(80000504)|T=QueryServer::TextService::ReplyTopic_01015e7d85f75b87425f8a618000a503|CREATE READCONDITION] DDS_TypeCode_dereference_member_name:member starting with [value = 1] not found
[D0100|Reader(80000504)|T=QueryServer::TextService::ReplyTopic_01015e7d85f75b87425f8a618000a503|CREATE READCONDITION] DDS_SqlFilter_compile:SQL compiler failed with error-code: -15 (Invalid symbol)
[D0100|Reader(80000504)|T=QueryServer::TextService::ReplyTopic_01015e7d85f75b87425f8a618000a503|CREATE READCONDITION] PRESPsReader_createReadOrQueryConditionI:content filter compile error 1
[D0100|Reader(80000504)|T=QueryServer::TextService::ReplyTopic_01015e7d85f75b87425f8a618000a503|CREATE READCONDITION] DDS_QueryCondition_createI:!create DDS_QueryCondition

It seems that the ".value" part of the sequence number is not recognized. I also tried to remove the ".value" part in the query expression and then I get this error:

[D0100|Reader(80000004)|T=QueryServer::TextService::ReplyTopic_01010076d3ab36d66bc1b8d480000003|CREATE READCONDITION] DDS_SqlFilter_symbol_lookup:symbol starting with [@related_sample_identity.sequence_number = 2] is not a primitive
[D0100|Reader(80000004)|T=QueryServer::TextService::ReplyTopic_01010076d3ab36d66bc1b8d480000003|CREATE READCONDITION] DDS_SqlFilter_compile:SQL compiler failed with error-code: -15 (Invalid symbol)
[D0100|Reader(80000004)|T=QueryServer::TextService::ReplyTopic_01010076d3ab36d66bc1b8d480000003|CREATE READCONDITION] PRESPsReader_createReadOrQueryConditionI:content filter compile error 1
[D0100|Reader(80000004)|T=QueryServer::TextService::ReplyTopic_01010076d3ab36d66bc1b8d480000003|CREATE READCONDITION] DDS_QueryCondition_createI:!create DDS_QueryCondition

So comparing the sequence_number directly also doesn't seem to work. What am I missing here? Can anybody help me?

Cheers

Alex