RFR JDK-8087113: Websocket API and implementation

Simone Bordet simone.bordet at gmail.com
Tue Apr 5 20:16:27 UTC 2016


Hi,

On Tue, Apr 5, 2016 at 9:37 PM, Chris Hegarty <chris.hegarty at oracle.com> wrote:
> I need to get back into the code, but are you counting the calling thread,
> the one invoking sendXXX(), as dispatch 1?

No, that's why I am proposing *zero* dispatches.

> We always need this to
> allow the caller NOT block right.

Sure, the caller must not block.
But there is no need to dispatch to achieve that when all code is
non-blocking already.

> Are you specifically saying that TEXT decoding, masking of the
> payload, and sending should all happen in a single task?

Yes. These are all in-memory operations that do not block (even I/O is
non-blocking).
It's not only text decoding, it's everything: the binary variant of
send(), and on the read side too.

No dispatches, no thread pools, no queues, no synchronization, no
deadlocks, huge simplification of the implementation and much more CPU
friendly.

> What the implementation does is to split these into separate tasks,
> so that they can be performed in parallel for large messages.

For a single thread calling send(), they are not performed in
parallel. They are performed sequentially across 3 dispatches.

If you mean different threads calling send(), then you already have parallelism.

If you mean the same thread calling send() in a tight loop, what you
want is exactly to push back the sender by performing the tasks in the
caller thread, rather than queuing and returning immediately.
Imagine 8 cores and 8 tight loops: the threads in the pool will have
little chance to run, causing the thread pool queue to grow
indefinitely.

> Are you suggesting that this is not really worth it? At least for small
> messages, or maybe not at all.  It would simplify the implementation
> somewhat.

I don't see any reason to perform 3 dispatches for a single send() -
not even 1 dispatch.
I am suggesting to do zero dispatches, independently from the size of
the message.

The only reason to perform a dispatch is to protect the implementation
from application code that may block.
This happens on the read side only, when the implementation is calling
WebSocket.Listener implementations - application code can block
forever.

Now, IMHO the WebSocket.Listener contract should be that applications
implementing WebSocket.Listener must not block.
If they do, they have to be equipped with a dispatching mechanism and
do it themselves. The API has already been designed with CFs to report
asynchronous completion.
If they do, and do not dispatch, then there are 2 solutions: the first
is to do nothing (same as when you call Socket.read() - by default it
waits forever), the second is to have a timeout that, when it fires,
automatically produces a CF that is completed exceptionally with a
TimeoutException for that invocation of the WebSocket.Listener method.
I would stay simple and do nothing.

IMHO the WebSocket implementation should not preemptively dispatch
calls to WebSocket.Listener methods, because that would hurt
applications that do not block - and we are going towards more and
more of this kind of applications.

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


More information about the net-dev mailing list