Skip to content

Commit eaa71bb

Browse files
glbrnttLukasa
andauthored
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]>
1 parent 6693a60 commit eaa71bb

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Multiplexing for maintainers
2+
3+
The term "multiplexer" appears in many types across ``NIOHTTP2``. This article
4+
explains the different ways stream multiplexing is achieved and how the pieces
5+
fit together.
6+
7+
The intended audience is _library maintainers_ although users may find it
8+
helpful too. It is not meant to be a comprehensive guide and assumes you have at
9+
least a high-level understanding of how the library is structured.
10+
11+
There are two high-level approaches to multiplexing in ``NIOHTTP2``:
12+
13+
1. _Legacy_ multiplexing is implemented as a separate `ChannelHandler`.
14+
2. _Inline_ multiplexing is implemented within the ``NIOHTTP2Handler``.
15+
16+
## Legacy
17+
18+
The _legacy_ multiplexer is a separate `ChannelHandler` which maintains the set
19+
of open child channels keyed by their stream ID. It is implemented as the
20+
``HTTP2StreamMultiplexer``. The handler receives frames and various channel
21+
events from the ``NIOHTTP2Handler`` which are acted upon or propagated to the
22+
appropriate child channel or forwarded down the connection channel. This
23+
approach makes heavy use of user-inbound events to pass additional information
24+
between the ``NIOHTTP2Handler`` and the ``HTTP2StreamMultiplexer``.
25+
26+
The child channels are wrapped up as `MultiplexerAbstractChannel`s: this is a
27+
wrapper around an `HTTP2StreamChannel` operating in one of two possible modes.
28+
The modes correspond to the type of data passed between the connection channel
29+
and the stream channels:
30+
31+
1. ``HTTP2Frame/FramePayload``
32+
2. ``HTTP2Frame``. All paths leading to this mode of operation are deprecated,
33+
see [Issue 214](https://github.com/apple/swift-nio-http2/issues/214) for more
34+
context.
35+
36+
## Inline
37+
38+
`_Inline_` multiplexing is the newer way of multiplexing streams and is
39+
implemented inline in the ``NIOHTTP2Handler``. It was created to reduce the cost
40+
of multiplexing incurred by the legacy multiplexer by removing the out-of-band
41+
passing of information as user-inbound events. Like the legacy multiplexer, it
42+
maintains a set of open stream channels and propagates events to them directly.
43+
This is implemented as the `NIOHTTP2Handler.InlineStreamMultiplexer`.
44+
45+
## How they fit together
46+
47+
Both methods are supported which goes some of the way to explaining why there
48+
are so many types with the word "multiplexer" in their name.
49+
50+
The ``NIOHTTP2Handler`` makes it possible to use either approach by abstracting
51+
them away behind the `HTTP2StreamMultiplexer` protocol. The two implementations
52+
(`LegacyInboundStreamMultiplexer` and `InlineStreamMultiplexer`) are wrapped up
53+
in an `enum` called `HTTP2InboundStreamMultiplexer` held by the
54+
``NIOHTTP2Handler``.
55+
56+
The `LegacyInboundStreamMultiplexer` just forwards events down the channel
57+
pipeline to the ``HTTP2StreamMultiplexer`` `ChannelHandler` which in turn calls
58+
into the `HTTP2CommonInboundStreamMultiplexer`.
59+
60+
The `NIOHTTP2Handler.InboundStreamMultiplexer` calls the
61+
`HTTP2CommonInboundStreamMultiplexer` directly.
62+
63+
The ``NIOHTTP2Handler`` propagates events to `HTTP2InboundStreamMultiplexer` but
64+
_also_ forwards events down the channel pipeline. Because of this, and to avoid
65+
events being delivered twice, some events on the
66+
`LegacyInboundStreamMultiplexer` are no-ops.
67+
68+
## The relevant pieces, briefly(-ish)
69+
70+
- **``NIOHTTP2Handler``**: a `public` `ChannelHandler` which decodes bytes to
71+
``HTTP2Frame``s (and vice versa). When operating in the 'inline' mode outbound
72+
streams can be _created_ (via ``NIOHTTP2Handler/StreamMultiplexer``). Inbound
73+
streams are demultiplexed via the `NIOHTTP2Handler.InboundStreamMultiplexer`.
74+
- **`HTTP2InboundStreamMultiplexer`**: an `internal` `protocol` which
75+
demuiltiplexes various inbound events (receiving frames, errors, etc.) into
76+
streams.
77+
- **`NIOHTTP2Handler.InboundStreamMultiplexer`**: an `internal` `enum` with two
78+
cases conforming to `HTTP2InboundStreamMultiplexer`. The `NIOHTTP2Handler`
79+
holds an instance of this internally.
80+
- **``NIOHTTP2Handler/StreamMultiplexer``**: a `public` `struct` which wraps
81+
`HTTP2InboundStreamMultiplexer` to provide API for creating outbound streams.
82+
- **``HTTP2StreamMultiplexer``**: a `public` `ChannelHandler` used for _legacy_
83+
multiplexing. which also allows you to _create_ outbound streams. Most of its
84+
internals call through to the `HTTP2CommonInboundStreamMultiplexer`.
85+
- **`LegacyInboundStreamMultiplexer`**: an `internal` `struct` which conforms to
86+
`HTTP2InboundStreamMultiplexer` and forwards various events down the channel
87+
pipeline (to the `HTTP2StreamMultiplexer` handler). One of the two cases of
88+
the `NIOHTTP2Handler.InboundStreamMultiplexer`.
89+
- **`HTTP2CommonInboundStreamMultiplexer`**: an `internal` `struct` which
90+
actually holds the set of open streams keyed by their ID and is responsible
91+
for propagating events to them.
92+
- **`InlineStreamMultiplexer`**: an `internal` `struct` which conforms to
93+
`HTTP2InboundStreamMultiplexer` and forwards events directly to the
94+
`HTTP2CommonInboundStreamMultiplexer`. The second case of the
95+
`NIOHTTP2Handler.InboundStreamMultiplexer`.
96+
- **`MultiplexerAbstractChannel`**: an `internal` `enum` with two cases which
97+
wraps an `HTTP2StreamChannel`. The two cases correspond to the type of data
98+
passed into the stream (``HTTP2Frame`` vs. ``HTTP2Frame/FramePayload``).

0 commit comments

Comments
 (0)