-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an article about multiplexing (#465)
Motivation: It's hard to keep track of all the pieces that do multiplexing. When making some changes I found myself writing down what each piece did and how they fit together. I think this is generally useful information for anyone maintaining the library. Modifications: - Add a DocC article about the different multiplexing approaches that's aimed at _maintainers_ of NIOHTTP2. Result: Easier to learn about how multiplexing is done --------- Co-authored-by: Cory Benfield <[email protected]>
- Loading branch information
Showing
1 changed file
with
98 additions
and
0 deletions.
There are no files selected for viewing
98 changes: 98 additions & 0 deletions
98
Sources/NIOHTTP2/Docs.docc/Articles/Multiplexing-for-maintainers.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# Multiplexing for maintainers | ||
|
||
The term "multiplexer" appears in many types across ``NIOHTTP2``. This article | ||
explains the different ways stream multiplexing is achieved and how the pieces | ||
fit together. | ||
|
||
The intended audience is _library maintainers_ although users may find it | ||
helpful too. It is not meant to be a comprehensive guide and assumes you have at | ||
least a high-level understanding of how the library is structured. | ||
|
||
There are two high-level approaches to multiplexing in ``NIOHTTP2``: | ||
|
||
1. _Legacy_ multiplexing is implemented as a separate `ChannelHandler`. | ||
2. _Inline_ multiplexing is implemented within the ``NIOHTTP2Handler``. | ||
|
||
## Legacy | ||
|
||
The _legacy_ multiplexer is a separate `ChannelHandler` which maintains the set | ||
of open child channels keyed by their stream ID. It is implemented as the | ||
``HTTP2StreamMultiplexer``. The handler receives frames and various channel | ||
events from the ``NIOHTTP2Handler`` which are acted upon or propagated to the | ||
appropriate child channel or forwarded down the connection channel. This | ||
approach makes heavy use of user-inbound events to pass additional information | ||
between the ``NIOHTTP2Handler`` and the ``HTTP2StreamMultiplexer``. | ||
|
||
The child channels are wrapped up as `MultiplexerAbstractChannel`s: this is a | ||
wrapper around an `HTTP2StreamChannel` operating in one of two possible modes. | ||
The modes correspond to the type of data passed between the connection channel | ||
and the stream channels: | ||
|
||
1. ``HTTP2Frame/FramePayload`` | ||
2. ``HTTP2Frame``. All paths leading to this mode of operation are deprecated, | ||
see [Issue 214](https://github.com/apple/swift-nio-http2/issues/214) for more | ||
context. | ||
|
||
## Inline | ||
|
||
`_Inline_` multiplexing is the newer way of multiplexing streams and is | ||
implemented inline in the ``NIOHTTP2Handler``. It was created to reduce the cost | ||
of multiplexing incurred by the legacy multiplexer by removing the out-of-band | ||
passing of information as user-inbound events. Like the legacy multiplexer, it | ||
maintains a set of open stream channels and propagates events to them directly. | ||
This is implemented as the `NIOHTTP2Handler.InlineStreamMultiplexer`. | ||
|
||
## How they fit together | ||
|
||
Both methods are supported which goes some of the way to explaining why there | ||
are so many types with the word "multiplexer" in their name. | ||
|
||
The ``NIOHTTP2Handler`` makes it possible to use either approach by abstracting | ||
them away behind the `HTTP2StreamMultiplexer` protocol. The two implementations | ||
(`LegacyInboundStreamMultiplexer` and `InlineStreamMultiplexer`) are wrapped up | ||
in an `enum` called `HTTP2InboundStreamMultiplexer` held by the | ||
``NIOHTTP2Handler``. | ||
|
||
The `LegacyInboundStreamMultiplexer` just forwards events down the channel | ||
pipeline to the ``HTTP2StreamMultiplexer`` `ChannelHandler` which in turn calls | ||
into the `HTTP2CommonInboundStreamMultiplexer`. | ||
|
||
The `NIOHTTP2Handler.InboundStreamMultiplexer` calls the | ||
`HTTP2CommonInboundStreamMultiplexer` directly. | ||
|
||
The ``NIOHTTP2Handler`` propagates events to `HTTP2InboundStreamMultiplexer` but | ||
_also_ forwards events down the channel pipeline. Because of this, and to avoid | ||
events being delivered twice, some events on the | ||
`LegacyInboundStreamMultiplexer` are no-ops. | ||
|
||
## The relevant pieces, briefly(-ish) | ||
|
||
- **``NIOHTTP2Handler``**: a `public` `ChannelHandler` which decodes bytes to | ||
``HTTP2Frame``s (and vice versa). When operating in the 'inline' mode outbound | ||
streams can be _created_ (via ``NIOHTTP2Handler/StreamMultiplexer``). Inbound | ||
streams are demultiplexed via the `NIOHTTP2Handler.InboundStreamMultiplexer`. | ||
- **`HTTP2InboundStreamMultiplexer`**: an `internal` `protocol` which | ||
demuiltiplexes various inbound events (receiving frames, errors, etc.) into | ||
streams. | ||
- **`NIOHTTP2Handler.InboundStreamMultiplexer`**: an `internal` `enum` with two | ||
cases conforming to `HTTP2InboundStreamMultiplexer`. The `NIOHTTP2Handler` | ||
holds an instance of this internally. | ||
- **``NIOHTTP2Handler/StreamMultiplexer``**: a `public` `struct` which wraps | ||
`HTTP2InboundStreamMultiplexer` to provide API for creating outbound streams. | ||
- **``HTTP2StreamMultiplexer``**: a `public` `ChannelHandler` used for _legacy_ | ||
multiplexing. which also allows you to _create_ outbound streams. Most of its | ||
internals call through to the `HTTP2CommonInboundStreamMultiplexer`. | ||
- **`LegacyInboundStreamMultiplexer`**: an `internal` `struct` which conforms to | ||
`HTTP2InboundStreamMultiplexer` and forwards various events down the channel | ||
pipeline (to the `HTTP2StreamMultiplexer` handler). One of the two cases of | ||
the `NIOHTTP2Handler.InboundStreamMultiplexer`. | ||
- **`HTTP2CommonInboundStreamMultiplexer`**: an `internal` `struct` which | ||
actually holds the set of open streams keyed by their ID and is responsible | ||
for propagating events to them. | ||
- **`InlineStreamMultiplexer`**: an `internal` `struct` which conforms to | ||
`HTTP2InboundStreamMultiplexer` and forwards events directly to the | ||
`HTTP2CommonInboundStreamMultiplexer`. The second case of the | ||
`NIOHTTP2Handler.InboundStreamMultiplexer`. | ||
- **`MultiplexerAbstractChannel`**: an `internal` `enum` with two cases which | ||
wraps an `HTTP2StreamChannel`. The two cases correspond to the type of data | ||
passed into the stream (``HTTP2Frame`` vs. ``HTTP2Frame/FramePayload``). |