eclipse-cyclonedds / cyclonedds

Eclipse Cyclone DDS project
https://projects.eclipse.org/projects/iot.cyclonedds
Other
884 stars 362 forks source link

Incorrect Ownership Strength Behavior with "EXCLUSIVE" Ownership Kind #1861

Open llddang opened 1 year ago

llddang commented 1 year ago

I have identified a violated behavior of Eclipse DDS concerning the ownership kind specified in Quality of Service (QoS). According to the specification, when the ownership kind is set to "EXCLUSIVE," only one DataWriter should have access rights to a data-object based on the ownership strength. However, in the current implementation, it allows two DataWriters to access the data-object, which is inconsistent with the expected behavior specified in the QoS.

Expected Behavior:

My domain configuration is like this.

Participant  ------------------------------------------------------
      |--------Publisher                                          |
      |           |-----------DataWriter1 ------------------------|
      |           |-----------DataWriter2 ------------------------|
      |---------Subscriber                                      Topic
                  |-----------DataReader -------------------------|

One Participant, Topic, Publisher, Subscriber, DataReader, and two DataWriters.

And qos as below:

dds_qos_t *wqos1 = dds_create_qos(); dds_qset_ownership(wqos1, DDS_OWNERSHIP_EXCLUSIVE); dds_qset_ownership_strength(wqos1, 10);

dds_qos_t *wqos2 = dds_create_qos(); dds_qset_ownership(wqos2, DDS_OWNERSHIP_EXCLUSIVE); dds_qset_ownership_strength(wqos2, 0);

dds_qos_t *rqos = dds_create_qos(); dds_qset_ownership(rqos, DDS_OWNERSHIP_EXCLUSIVE);

Actual Behavior:

Steps to Reproduce:

This is my whole code for reproduce.

#include <map>
#include <fstream>
#include <sstream>
#include <unistd.h>
#include <iostream>

#include "dds/dds.h"
#include "HelloWorldData.h"

using namespace std;

void on_data_available(dds_entity_t reader, void* arg);

int main(int argc, char** argv){
    /* create participant */
    dds_entity_t participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);

    /* create topic */
    dds_entity_t topic = dds_create_topic(participant, &HelloWorldData_Msg_desc, "HelloWorldData_Msg", NULL, NULL);

    /* create publisher */
    dds_entity_t publisher = dds_create_publisher(participant, NULL, NULL);

    /* setting the writer1 qos */
    dds_qos_t *wqos1 = dds_create_qos();
    dds_qset_ownership(wqos1, DDS_OWNERSHIP_EXCLUSIVE);
    dds_qset_ownership_strength(wqos1, 10);

    /* create writer1 */
    dds_entity_t writer1 = dds_create_writer(publisher, topic, wqos1, NULL);
    dds_delete_qos(wqos1);

    /* setting the writer2 qos */
    dds_qos_t *wqos2 = dds_create_qos();
    dds_qset_ownership(wqos2, DDS_OWNERSHIP_EXCLUSIVE);
    dds_qset_ownership_strength(wqos2, 0);

    /* create writer2 */
    dds_entity_t writer2 = dds_create_writer(publisher, topic, wqos2, NULL);
    dds_delete_qos(wqos2);

    /* create the subscriber */
    dds_entity_t subscriber = dds_create_subscriber(participant, NULL, NULL);

    /* setting the reader qos */
    dds_qos_t *rqos = dds_create_qos();
    dds_qset_ownership(rqos, DDS_OWNERSHIP_EXCLUSIVE);

    /* create reader */
    dds_entity_t reader = dds_create_reader(subscriber, topic, rqos, NULL);
    dds_delete_qos(rqos);

    /* setting the reader listener */
    dds_listener_t *reader_listener = dds_create_listener(NULL);
    dds_lset_data_available(reader_listener, on_data_available);
    dds_set_listener(reader, reader_listener);
    dds_delete_listener(reader_listener);

    sleep(1);

    /* wirter write the message */
    HelloWorldData_Msg hello_1;
    hello_1.userID = 1;
    hello_1.message = "Hello World 1";
    std::cout << "Message: " << hello_1.message << " with index: " << hello_1.userID << " SENT" << std::endl;
    dds_write (writer1, &hello_1);

    HelloWorldData_Msg hello_2;
    hello_2.userID = 2;
    hello_2.message = "Hello World 2";
    std::cout << "Message: " << hello_2.message << " with index: " << hello_2.userID << " SENT" << std::endl;
    dds_write (writer2, &hello_2);

    /* sleep */
    sleep(3);

    /* delete everything */
    dds_delete(participant);

    return 0;
}

/* reader listener callback function */
void on_data_available(dds_entity_t reader, void* arg){
    void * samples[1];
    dds_sample_info_t infos[1];

    /* Initialize sample buffer, by pointing the void pointer within
     * the buffer array to a valid sample memory location. */
    samples[0] = HelloWorldData_Msg__alloc ();

    int samples_received = dds_take(reader, samples, infos, 1, 1);
    if ((samples_received > 0) && (infos[0].valid_data)){
        HelloWorldData_Msg * msg = (HelloWorldData_Msg*) samples[0];

        std::cout << "< READER : on_data_available > reader get message " << msg->message << " from " << msg->userID << " RECEIVED" << std::endl; 
    }

    /* Free the data location. */
    HelloWorldData_Msg_free (samples[0], DDS_FREE_ALL);
}

Environment:

hansvanthag commented 1 year ago

Note that ownership is on a 'per instance' basis so please make sure that your 2 writers are publishing the same instance (as its perfectly fine if the 'owner' of instance A is different from the 'owner' of instance B. I didn't check the IDL but in case the userID in the data-model would be a key, the observed behavior would be correct.

hansvanthag commented 1 year ago

... looking at the HelloWorld example, its indeed the case that the userID is a key so my assumption was correct and the observed behavior is too .. to check exclusive ownership you should use the same userID for both writers and see if it works as expected this time ;)

llddang commented 1 year ago

Thank you for your quick reply. From the explanation, it seems that my understanding of specification is still unclear. I will clearly understand the contents of the specification and check it through the experiment.

Best regard