Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only serialize key when C function asks for a key #273

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

eboasson
Copy link
Contributor

For some operations, the DDS API requires a key instead of a sample ("dispose" is one of those), and does this by invoking the "ddsi_serdata_from_sample" operation with kind set to "SDK_KEY".

The Python binding is a bit unusual in that it serializes the data before calling into C because that allows using Python code to serialize the data without having to call back into Python code from C or being forced to interpret Python objects from C. A mismatch is possible, and this causes failures if the serialized form of the key is not a prefix of the serialized form of the full sample. For example:

@dataclass
class S(idl.IdlStruct, typename="S"):
    v: int
    k: int
    key("k")

ih0 = dw.register_instance(S(0, 1))

Will misinterpret the bytes and treat the key value as 0 instead of as 1.

It can be dealt with in two ways:

  • One is to continue always serializing a full sample in Python, fixing it up in the serdata implementation if a serialized key is requested. This is small change in the Python "clayer";
  • The other is to serialize a key when a key is expected. This is somewhat fragile, but the list of operations is small and the API rather stable.

This commit implements the second option, and mostly because it means the serializer will not touch the non-key fields.

Intended to fix #269

For some operations, the DDS API requires a key instead of a sample ("dispose" is one of
those), and does this by invoking the "ddsi_serdata_from_sample" operation with kind set
to "SDK_KEY".

The Python binding is a bit unusual in that it serializes the data before calling into C
because that allows using Python code to serialize the data without having to call back
into Python code from C or being forced to interpret Python objects from C.  A mismatch is
possible, and this causes failures if the serialized form of the key is not a prefix of
the serialized form of the full sample.  For example:

    @DataClass
    class S(idl.IdlStruct, typename="S"):
        v: int
        k: int
        key("k")

    ih0 = dw.register_instance(S(0, 1))

Will misinterpret the bytes and treat the key value as 0 instead of as 1.

It can be dealt with in two ways:

* One is to continue always serializing a full sample in Python, fixing it up in the
  serdata implementation if a serialized key is requested.  This is small change in the
  Python "clayer";

* The other is to serialize a key when a key is expected. This is somewhat fragile, but
  the list of operations is small and the API rather stable.

This commit implements the second option, and mostly because it means the serializer will
not touch the non-key fields.

Signed-off-by: Erik Boasson <[email protected]>
Copy link
Contributor

@dpotman dpotman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I have only two minor points noted below.

raise Exception("Cannot encode this type with version 0, contains xcdrv2-type structures")
use_version_2 = True

if self.keyless:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this early-out not needed in the generic seralized, can that function be called in SerializeKind.Key... mode for a keyless type?

@@ -371,7 +371,7 @@ def wait_for_historical_data(self, timeout: int) -> bool:
raise DDSException(ret, f"Occured while waiting for historical data in {repr(self)}")

def lookup_instance(self, sample: _T) -> Optional[int]:
ret = ddspy_lookup_instance(self._ref, sample.serialize())
ret = ddspy_lookup_instance(self._ref, sample.serialize_key())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect that this serialize also needs padding \0s, similar to pub.lookup_instance?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Instance Registration and Disposal fails
2 participants