Hi,

On Sat, Jun 11, 2016 at 1:20 PM, Pavel Rappo <pavel.ra...@oracle.com> wrote:
> Simone,
>
> What's your opinion on how send(Ping|Pong|Close) should work? I mean with "one
> outstanding send" policy you're advocating for, should all types of messages
> sent by an app honor this policy?
>
> If we allow Pings, unsolicited Pongs and Close messages to jump ahead of the
> "queue" and define this as an implementation specific detail, then we might 
> run
> into one of these traps you've mentioned. When the same application might work
> pretty differently against different implementations.

Pings should be sent as soon as possible as per specification, and
this is implementation dependent.
Unsolicited pongs, never seen them used, but I'd guess same behavior as above.
Close should definitely *not* "jump ahead of the queue", it should be
sent after queued stuff has been sent.

> Should the application be in charge of chopping outgoing messages in chunks in
> order to provide better responsiveness when needed?

Not sure what you mean here.

The current API allows for partial messages. That does not mean that
every call correspond to a frame.
The reason for this API is to provide a handy way to be able to read
from an InputStream and convert the whole stream into a single
WebSocket message.
In this case the application is "in charge of chopping" in the sense
that it is how the application works.
I would not give any other "chopping" semantic to the API rather than
just a utility method to write messages when the whole message is not
completely available upfront.

To me, pings (let's leave out unsolicited pongs) are an application
mean to measure roundtrip; because they can be interleaved at the
protocol level, I may be interested in knowing when they are fully
written, but I would not make this interfere with message sending.
Say for example you have a scheduler that sends pings every X seconds,
you don't want an application to coordinate with this in order to send
messages. The application will eventually coordinate with the onPong()
response to tune the buffer size based on the roundtrip time, or
things like that.

I see the "at most one outstanding write" at the send message level
only because it has the danger of infinite buffering.
Pings are limited at 125 bytes, so yes you can still blow up the heap
if you send a gazillion of them in a tight loop, but it's a degenerate
case.

On the other hand it would be very easy to blow up the heap reading
and sending a large file, not to mention the buffer semantic.
For example, a naive implementation to read from a huge file:

FileChannel huge = ...;
ByteBuffer buffer = ...;
long start = 0;
while (true) {
  int read = huge.read(buffer, start);
  if (read < 0) {
    ws.sendBinary(ByteBuffer.allocate(0), true);
    break;
  } else {
    start += read;
    buffer.flip();
    ws.sendBinary(buffer, false);
  }
}

This code has 2 problems: allows for infinite buffering, and it's not
clear for the application when it can reuse the buffer.
An implementation *must* copy the buffer data if it allows for
multiple outstanding writes, causing even more memory pressure.

If the application solves the buffer problem (because the
implementation semantic is to *not* copy), then it has at most one
outstanding write, and as such also the infinite buffering problem is
solved.

It's all about the semantic you want to give to the API.

If you say: "Implementations *must* ensure infinite buffering and data
copy semantic" then it's ok.
If you say: "Implementations don't copy data, so applications must be
careful with buffers", it's ok too.
If you say: "Implementations are free to do whatever they want", then
it's ok too.

For each of those there are additional burdens on applications, but at
least it's clear to an application what it should do.

If you choose the last, then an application has to assume the least,
and it has to write code with only one outstanding write.
At that point you (as implementer) have the burden of putting in the
API javadocs the correct examples, and explain why the snippet above
is wrong.

Thanks !

-- 
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz

Reply via email to