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