Skip to content

Populate type hashes in graph cache names_and_types (#356)#89

Open
tisomi wants to merge 1 commit into
ros2:rollingfrom
tisomi:rolling
Open

Populate type hashes in graph cache names_and_types (#356)#89
tisomi wants to merge 1 commit into
ros2:rollingfrom
tisomi:rolling

Conversation

@tisomi

@tisomi tisomi commented Jul 2, 2026

Copy link
Copy Markdown

Description

This PR populates the new type_hashes field on rmw_names_and_types_t from the discovery
data held in GraphCache, so DDS-based rmw implementations (rmw_fastrtps, rmw_cyclonedds,
rmw_connextdds) report the type hash of each name/type pair through the graph query APIs.
It is the middleware counterpart to the interface change in ros2/rmw#356.

Key changes:

  • The internal aggregation type is widened from
    std::map<std::string, std::set<std::string>> to
    std::map<std::string, std::map<std::string, rosidl_type_hash_t>> — i.e. the per-topic
    container changes from a set of type names to a map from each type name to its hash.
    So every type under a topic now carries its hash through to the caller. The type name
    stays the (inner) map key, preserving the existing de-duplication.
  • Both graph query paths are covered: the global get_names_and_types and the per-node
    get_reader_names_and_types_by_node / get_writer_names_and_types_by_node.
  • Service vs. topic hash selection: a ROS service is represented on DDS as a request/reply
    topic pair, so a service endpoint has both a per-direction message hash (topic_type_hash,
    which differs between server and client side) and the service descriptor hash
    (service_type_hash, identical on both sides and the value the user expects).
    _select_hash_for_entity returns the service-level hash when the entity is registered as a
    service (present in data_services_) and falls back to the topic-level hash otherwise.
    data_services_ is threaded through the internal helpers so this also works on the
    by-node paths.
  • Conflict handling: when the same type on a topic carries different hashes across
    endpoints, a WARN is logged and a zero-initialized hash is stored so the caller sees an
    unambiguous "no consensus" value (matching the rmw_zenoh behavior). See Additional Information
    for why this can occur.
  • __populate_rmw_names_and_types allocates the per-name hash array (or nullptr when a
    name has no types) and copies each hash alongside the corresponding type name. Its error
    handling was refactored to a single goto cleanup path that finalizes the partially-built
    struct via rmw_names_and_types_fini.

Adds graph-cache tests covering the populated hashes for both the global and per-node paths.

Related: ros2/rmw#356

Is this user-facing behavior change?

Yes.

  • The graph query APIs (rmw_get_topic_names_and_types, rmw_get_service_names_and_types,
    and the per-node variants) now report the type hash of each name/type pair via the new
    type_hashes array.
  • When endpoints disagree on the hash for the same (topic, type) pair, the reported hash is
    a zero hash and a WARN is logged.
  • No public signature changes in this package; it populates the existing output field. It
    requires the ABI-breaking struct change from Extend names_and_types to contain type hashes rmw#356.

Did you use Generative AI?

Yes. Claude (claude-sonnet-4-6) via GitHub Copilot was used to explore the codebase and
create an initial prototype.

Additional Information

  • Depends on the interface PR ros2/rmw#421, which adds the type_hashes field and hardens
    rmw_names_and_types_init / rmw_names_and_types_fini. The goto cleanup path here relies
    on fini cleaning up partially-populated structs without leaking.
  • Companion PR: rmw_zenoh #1004 "Populate type hashes in zenoh graph cache".
  • The endpoint-level topic_type_hash and the data_services_ map already existed in the
    cache; this PR wires them into the names_and_types output.

On the hash-conflict case. A single topic name can appear with more than one type in
the ROS graph, which is why rmw_names_and_types_t stores an array of types per name.
Beyond that, two entries can share the same type name while the type definitions behind
them differ structurally — different versions of the same interface — and therefore produce
different hashes. This "version drift" arises when nodes on the graph are built against
different versions of the same type definition. When it happens, the graph query reports a
zero hash for that type and logs a WARN. In a version-consistent system this should not
occur, but the graph layer has to surface it rather than hand the caller one endpoint's
hash as if it were authoritative.

Testing

  • Ran the package unit tests (including the new graph-cache hash cases) in a Docker
    container; all pass.
  • Implemented and successfully ran an integration test exercising the end-to-end type-hash
    path through the graph query APIs.

This is a SIEMENS activity and was initialized by @gramss

Populates the new type_hashes field on rmw_names_and_types_t from the
entries in GraphCache. The internal map is widened from
std::set<std::string> to std::map<std::string, rosidl_type_hash_t>
so each (topic, type) pair carries its hash through to the rmw caller,
covering both the global get_names_and_types and per-node paths.

When the same (topic, type) pair carries different hashes across
endpoints, the conflict is detected and a WARN-level log is emitted;
the stored hash is replaced with a zero hash so the caller sees an
unambiguous "no consensus" value, matching the rmw_zenoh behavior.

Adds graph-cache tests covering the populated hashes for both paths.

Related: ros2/rmw#356

Signed-off-by: tisomi <titus090404@gmail.com>
@mergify

mergify Bot commented Jul 2, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

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.

1 participant