Skip to content
This repository has been archived by the owner on Aug 11, 2023. It is now read-only.

Adding TCP-NO-DELAY transport hint #295

Merged
merged 3 commits into from
Apr 10, 2019
Merged

Conversation

StefanGlaser
Copy link
Contributor

This pull request introduces transport hints to specify the TCP-NO-DELAY option when creating a new subscriber. Furthermore, it also processes the TCP-NO-DELAY header field for incoming subscriber connections and sets this option on the corresponding channel.

For testing purposes I've modified the pubsub tutorial to exchange messages in 1000Hz. I've tested rosjava (subscriber) to rosjava (publisher) as well as rosjava (subscriber) to rospy (publisher). The roscore and subscriber were running on my PC and the publisher on a RasPi 3b, connected via a dedicated router. The transmitted messages were monitored in Wireshark. Both tests worked as expected.

Wireshark results:

  1. TCP-NO-DELAY on
    rosjava_tcp_no_delay_on

  2. TCP-NO-DELAY off
    rosjava_tcp_no_delay_off

The packets in the second screenshot that are not present in the first screenshot are packets that contain more than one ros message.

As there exists a connection buffer / pool in rosjava, I'm not 100% sure what happens if there are two subscribers to the same topic within a rosjava process, one with TCP-NO-DELAY disabled and one with the option enabled. My current expectation is that the first connection that is established decides if TCP-NO-DELAY is enabled or disabled for the corresponding channel. I didn't include the transport hints within the equals method of the TopicDeclaration class, as I wasn't sure what effects this will imply.

This pull request solves issue #292.

* Added TransportHints class, currently only containing a TCP-NO-DELAY option.
* Added option to specify transport hints when subscribing to a topic.
* Added transport hints to TopicDeclaration class.
* Check incoming subscriber connection requests for the TCP-NO-DELAY header field and set the TCP-NO-DELAY option on the corresponding channel accordingly.
@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here (e.g. I signed it!) and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@StefanGlaser
Copy link
Contributor Author

I signed it!

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@googlebot googlebot added cla: yes and removed cla: no labels Apr 3, 2019
@StefanGlaser
Copy link
Contributor Author

...even though I don't like it very much. Or maybe I don't understand it...

Copy link

@jubeira jubeira left a comment

Choose a reason for hiding this comment

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

Really cool @StefanGlaser!

I'd like to give it a shot before approving and merging, but overall it looks good!
By any chance have you tested this with cross-language publishers / subscribers? I'd like to verify that this feature works e.g. with rospy or roscpp as well to double check.

@StefanGlaser
Copy link
Contributor Author

Thanks @jubeira! I would also like to take the opportunity to thank you all for this project!

No hurry, take your time for testing.

Regarding cross-language support:
I've successfully tested rosjava (listener) in combination with rospy (publisher) as mentioned above. The messages transmitted during a subscription contain the tcp_nodelay key as can be seen in the Wireshark screenshots. So I expect this patch to be compatible to roscpp and rospy. Still, I'm looking forward to run some additional tests, as I'm also interested to see what happens if I have two subscribers to the same topic within one rosjava process.

@jubeira
Copy link

jubeira commented Apr 4, 2019

I've successfully tested rosjava (listener) in combination with rospy (publisher) as mentioned above.

Great! Sorry, I think I missed that part the first time I read the post.
I'll try to get this tested before EOW. Thanks again!

Copy link

@jubeira jubeira left a comment

Choose a reason for hiding this comment

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

First pass done!
I've left a few comments: some minor nitpicks, and some details on TransportHints; other than that it looks good.

I ran the test with both publisher and subscriber in the same system and I noticed no difference when using TCP_NODELAY. I guess that's expected anyways; I'll try with two different systems later.


Map<String, String> options;

public TransportHints() {
Copy link

Choose a reason for hiding this comment

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

nitpick: please indent functions and code with two spaces (same applies for next line).


public TransportHints tcpNoDelay(boolean nodelay) {
options.put(ConnectionHeaderFields.TCP_NODELAY, nodelay ? "1" : "0");

Copy link

Choose a reason for hiding this comment

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

nitpick: remove newline.

}

public TransportHints(boolean tcpNoDelay) {
tcpNoDelay(tcpNoDelay);
Copy link

Choose a reason for hiding this comment

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

This constructor yields a NullPointerException when called, as the default constructor is not called and therefore the map is not created.

Please consider either:

  • Calling the default constructor first.
  • Moving the initialization of the map to an instance initializer.
  • Initialize options inline (i.e. Map<String, String> options = Maps.newConcurrentMap<String, String>();).

I know in Java 7 it's not necessary to specify <String, String> twice, but please do so so as to make it easier to compile rosjava for older Java versions.

*/
public class TransportHints {

Map<String, String> options;
Copy link

Choose a reason for hiding this comment

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

nit: add private access specifier.

* Replaced internal map with simple boolean.
* Fixed initialization bug.
* Fixed code style.
@StefanGlaser
Copy link
Contributor Author

Thanks a lot for your feedback!
Sorry for all the inconveniences. I'm a bit confused by the number of mistakes I committed...

I've addressed your points in a new commit, in which I also replaced the internal map of the TransportHints class with a simple boolean attribute. This reduces the class dependencies and is a much more elegant solution to the given task in my opinion.

Great to hear that first tests didn't show any problems. The effect of TCP_NODELAY is very different depending on your setup. Even in my distributed setup I only get a couple of combined messages every now and then. But it's not only about the fact that multiple messages may be transmitted in one tcp packet. It's also about internal transmission delays. TCP_NODELAY should reduce the overall delay between the write call and the actual transmission of the corresponding tcp packet. However, checking for multiple messages transmitted in one tcp packet helps verifying that TCP_NODELAY works.

@jubeira
Copy link

jubeira commented Apr 9, 2019

Sorry for all the inconveniences. I'm a bit confused by the number of mistakes I committed...

No worries! That's what the reviews are for ;) thanks for addressing everything!
I'll give it a shot tomorrow using two different systems once more; I don't have the hardware with me right now. Codewise it looks good, so I'll likely get this approved and merged this week.

Thanks again @StefanGlaser!

Copy link

@jubeira jubeira left a comment

Choose a reason for hiding this comment

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

LGTM!
I've just tested the patch in two different systems and indeed, the new option generates the effect described above.

Just for the record, I noticed that if the hints between publisher and subscriber don't match, the Java subscriber is the option that prevails (tested with rospy publisher). In other words:

Java subscriber tcpnodelay Python publisher tcpnodelay Nodelay effect verified in Wireshark
No No No
No Yes No
Yes No Yes
Yes Yes Yes

@jubeira jubeira merged commit 111c1d1 into rosjava:kinetic Apr 10, 2019
@jubeira
Copy link

jubeira commented Apr 10, 2019

@StefanGlaser do you need a binary / Maven release with this change, or can you wait a little longer building from sources?

@StefanGlaser
Copy link
Contributor Author

Yeah, reviews are essential and we just approved it again - unfortunately ;)

Great work on checking the effect of TCP_NODELAY. The results look fine and as expected. However, you only checked one part of it. You didn't check if rosjava handles the flag for incoming subscriber connections, in case the publisher is written in rosjava. This was the mistake I did when falsely claiming rosjava already respects the TCP_NODELAY flag.

I'm looking forward to switch our project to maven, soon. So in theory yes, a new release would be nice. However, I would prefer to help getting a rosjava release for melodic done, as it may also help others and shows that this project is still active.

@jubeira
Copy link

jubeira commented Apr 12, 2019

However, you only checked one part of it. You didn't check if rosjava handles the flag for incoming subscriber connections, in case the publisher is written in rosjava. This was the mistake I did when falsely claiming rosjava already respects the TCP_NODELAY flag.

Yes, that's right, but in that sense I trust the tests you did before.

I'm looking forward to switch our project to maven, soon. So in theory yes, a new release would be nice. However, I would prefer to help getting a rosjava release for melodic done, as it may also help others and shows that this project is still active.

I'm on it! I need some more time to bump all the necessary versions and dependencies, which is a bit tedious and maybe a bit error-prone. If you are willing to volunteer, I might ping you to give it a shot once everything is on its place. Does that sound good?

@StefanGlaser
Copy link
Contributor Author

Hey, sry, totally forgot to answer...

That sounds great! I'm happy to volunteer. Feel free to ping me whenever you need.

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

Successfully merging this pull request may close these issues.

3 participants