add BackpressureBuffer, see #3253

- also make a Write’s “ack” be a Tcp.Event (to suit pipelines)
- add stress test for BackpressureBuffer
- add it to SslTlsSupportSpec
- add it to the docs
This commit is contained in:
Roland 2013-05-26 10:58:55 +02:00
parent 025a91ecc2
commit ea5b79e562
15 changed files with 764 additions and 248 deletions

View file

@ -563,7 +563,7 @@ resending of all queued data:
It should be noted that all writes which are currently buffered have also been
sent to the connection actor upon entering this state, which means that the
:class:`ResumeWriting` message is enqueued after those writes, leading to the
reception of all outstanding :class:`CommandFailre` messages (which are ignored
reception of all outstanding :class:`CommandFailed` messages (which are ignored
in this state) before receiving the :class:`WritingResumed` signal. That latter
message is sent by the connection actor only once the internally queued write
has been fully completed, meaning that a subsequent write will not fail. This
@ -590,36 +590,55 @@ first look at the SSL server:
.. includecode:: code/docs/io/japi/SslDocTest.java#server
Please refer to `the source code`_ to see all imports.
.. _the source code: @github@/akka-docs/rst/java/code/docs/io/japi/SslDocTest.java
The actor above binds to a local port and registers itself as the handler for
new connections. When a new connection comes in it will create a
:class:`javax.net.ssl.SSLEngine` (details not shown here since they vary wildly
:class:`javax.net.ssl.SSLEngine` (details not shown here since they vary widely
for different setups, please refer to the JDK documentation) and wrap that in
an :class:`SslTlsSupport` pipeline stage (which is included in ``akka-actor``).
This single-stage pipeline will be driven by a :class:`TcpPipelineHandler`
actor which is also included in ``akka-actor``. In order to capture the generic
command and event types consumed and emitted by that actor we need to create a
wrapper—the nested :class:`Init` class—which also provides the
:meth:`makeContext` method for creating the pipeline context needed by the
supplied pipeline. With those things bundled up all that remains is creating a
This sample demonstrates a few more things: below the SSL pipeline stage we
have inserted a backpressure buffer which will generate a
:class:`HighWatermarkReached` event to tell the upper stages to suspend writing
(generated at 10000 buffered bytes) and a :class:`LowWatermarkReached` when
they can resume writing (when buffer empties below 1000 bytes); the buffer has
a maximum capacity of 1MB. The implementation is very similar to the NACK-based
backpressure approach presented above. Above the SSL stage comes an adapter
which extracts only the payload data from the TCP commands and events, i.e. it
speaks :class:`ByteString` above. The resulting byte streams are broken into
frames by a :class:`DelimiterFraming` stage which chops them up on newline
characters. The top-most stage then converts between :class:`String` and UTF-8
encoded :class:`ByteString`.
As a result the pipeline will accept simple :class:`String` commands, encode
them using UTF-8, delimit them with newlines (which are expected to be already
present in the sending direction), transform them into TCP commands and events,
encrypt them and send them off to the connection actor while buffering writes.
This pipeline is driven by a :class:`TcpPipelineHandler` actor which is also
included in ``akka-actor``. In order to capture the generic command and event
types consumed and emitted by that actor we need to create a wrapper—the nested
:class:`Init` class—which also provides the the pipeline context needed by the
supplied pipeline; in this case we use the :meth:`withLogger` convenience
method which supplies a context that implements :class:`HasLogger` and
:class:`HasActorContext` and should be sufficient for typical pipelines. With
those things bundled up all that remains is creating a
:class:`TcpPipelineHandler` and registering that one as the recipient of
inbound traffic from the TCP connection.
Since we instructed that handler actor to send any events which are emitted by
the SSL pipeline to ourselves, we can then just wait for the reception of the
decrypted payload messages, compute a response—just ``"world"`` in this
case—and reply by sending back a ``Tcp.Write``. It should be noted that
decrypted payload messages, compute a response—just ``"world\n"`` in this
case—and reply by sending back an ``Init.Command``. It should be noted that
communication with the handler wraps commands and events in the inner types of
the ``init`` object in order to keep things well separated. To ease handling of
such path-dependent types there exist two helper methods, namely
:class:`Init.command` for creating a command and :class:`Init.event` for
unwrapping an event.
.. warning::
The :class:`TcpPipelineHandler` does currently not handle back-pressure from
the TCP socket, i.e. it will just lose data when the kernel buffer
overflows. This will be fixed before Akka 2.2 final.
Looking at the client side we see that not much needs to be changed:
.. includecode:: code/docs/io/japi/SslDocTest.java#client