Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP/2 Framing layer implementation (#309). #1233

Merged
merged 17 commits into from
May 16, 2019
Merged

Conversation

aleksostapenko
Copy link
Contributor

@aleksostapenko aleksostapenko commented Mar 28, 2019

Working HTTP/2 functionality in PR

  1. PING and SETTINGS frames exchange: receiving, parsing and response with ACK; tested via h2i utility (https://github.com/golang/net/tree/master/http2/h2i);
  2. Establishing HTTP/2 connection; tested via nghttp utility - the part of nghttp2/nghttp2-client packages (https://nghttp2.org):
    1. Client's connection preface (starting magic sequence and SETTINGS frame) receiving and parsing;
    2. Response with server side preface (initial SETTINGS frame);
    3. Send SETTINGS ACK frame (in response to client's preface SETTINGS frame);
    4. Receiving and parsing client's SETTINGS ACK frame (in response to server side preface SETTINGS fram
    5. Receiving and parsing client's PRIORITY frames;
    6. Receiving and parsing client's HEADERS frame;
    7. Applying client's HEADERS as initial frame for new stream creation.

Command:

nghttp -v https://<name_of_host_with_started_tempesta_fw>

Note: to test HTTP/2 connection establishing via nghttp (described above) - it is necessary to replace the implementation of APP_FRAME() macro with simple false value, since upper level for processing of application frames (HEADERS, DATA and CONTINUATION) is not implemented yet.

HTTP/2 Stream Scheduler

In context of #309 only base implementation of priority/dependency scheduler is planned (the rest must be implemented in #1196). So this PR contains only initial form of scheduler: at stage of #309 all streams are assumed to have equal weights and depends on the one root logical stream (with ID equal 0); thus, streams are processed in order of their frames/request/response come from TCP connection, and in this case we need just a simple streams' storage with fast search by ID. In current PR red-black tree based storage is used; this structure has been chosen - compared to hash table - due to lack of per-connection memory overhead, since for hash table some amount of memory (maybe large enough) must be allocated initially - at the connection's creation moment, and besides, this could be a ddos vector.

Considering future priority/dependency scheduler implementation in context of #1196 - an appropriate scheme for the scheduler, in my opinion, would be a tree-like structure (let's call it a dependency tree), built with the help of, "parent" and "child" pointers (embedded into Stream structure) for vertical links and "prev" and "next" pointers - for the horizontal links between neighbor streams of the same level. A logical stream with identifier 0 acts as a root of this tree. In addition to the specified links, each stream has a pointer to a special priority queue (based on the binary heap), in which only its child single-level streams with jobs to be processed (frames/requests/responses) are placed.

Thus, the red-black tree, mentioned above, in proposed scheme acts as a basic storage structure for a quick search of streams; on top of it - the dependency tree acts as a structure to track current dependencies between streams and to calculate effective priorities for each stream in the tree — based on their weights (in case of re-prioritization etc.); also dependency tree provides up/down traversals between dependency levels; and the priority queues, in turn, track the next stream to be processed for each level.

tempesta_fw/http_frame.c Show resolved Hide resolved
tempesta_fw/http_frame.c Outdated Show resolved Hide resolved
tempesta_fw/http_frame.c Outdated Show resolved Hide resolved
tempesta_fw/http_frame.c Outdated Show resolved Hide resolved
Copy link
Contributor

@i-rinat i-rinat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks OK.


#define VERIFY_FRAME_SIZE(ctx) \
do { \
if ((ctx)->hdr.length <= 0) \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scanned through the http/2 description, but found no evidence of zero-length frames are forbidden. In fact, 6.9.1 mentions them explicitly: "Frames with zero length with the END_STREAM flag set (that is, an empty DATA frame) MAY be sent if there is no available space in either flow-control window."
Some client may send such zero-length frames. I think we should allow that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added handling for zero length payload.

}

T_FSM_STATE(HTTP2_RECV_FRAME_SETTINGS) {
BUG_ON(ctx->to_read > FRAME_HEADER_SIZE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose to move this BUG_ON() into FRAME_FSM_READ_SRVC(), and change FRAME_HEADER_SIZE to sizeof(ctx->rbuf).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* certain service data should be separated from it (placed at the
* frame's beginning): frame header, optional pad length and optional
* priority data (the latter is for HEADERS frames only). Besides,
* DATA and HEADERS frames can containing some padding in the frame's
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* DATA and HEADERS frames can containing some padding in the frame's
* DATA and HEADERS frames can contain some padding in the frame's

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

* DATA and HEADERS frames can containing some padding in the frame's
* tail, but we don't need to worry about that here since such padding
* is processed as service data, separately from app frame, and it
* will be just splitted into separate skb (above).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* will be just splitted into separate skb (above).
* will be just split into separate skb (above).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

}

/*
* Initialization of HTTP/2 framing context. Due to passing frames to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more like re-initialization, as there is a period where context is used, but this function wasn't called yet. As far as I can see, context is initialized in tfw_tls_check_alloc_h2_context().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.


#define FRAME_CLI_MAGIC "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
#define FRAME_CLI_MAGIC_LEN 24
#define FRAME_SRVC1_SIZE 4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd propose to use separate constants for WINDOW_UPDATE and RST_STREAM. Hiding both behind SRVC1 doesn't save anything, but makes code harder to read. Same for SRVC2.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

#define FRAME_CLI_MAGIC_LEN 24
#define FRAME_SRVC1_SIZE 4
#define FRAME_PRIORITY_SIZE 5
#define FRAME_STNGS_ENTRY_SIZE 6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't help but read STNGS as "stings". Is it worth to save letters like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

break;

default:
/* Only DATA and HEADERS frames cab be padded. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/* Only DATA and HEADERS frames cab be padded. */
/* Only DATA and HEADERS frames can be padded. */

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

protos[order].id = TTLS_ALPN_ID_HTTP1;
protos[!order].name = TTLS_ALPN_HTTP2;
protos[!order].len = sizeof(TTLS_ALPN_HTTP2) - 1;
protos[!order].id = TTLS_ALPN_ID_HTTP2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like HTTP/2 is unconditionally enabled even if listen directive has https:http1 and doesn't mention http2 at all. Is this intended behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, currently http1 is just a shortcut for http1,http2 and http2 is a shortcut for http2,http1. Thus, we always enable http2 handling, and since our protocols order takes precedence, we can define what protocol will be used when client sends us in any order both http/1.1 and h2 in ALPN.
But in any case, this point (as well as the names for HTTP/1.1 and HTTP/2 protocols in configuration) remains the subject TBD.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not a good idea to enable HTTP/2 by default before we have the stable implementation - this may lead to bad user experience. I also vote for RFC compliant name like h2.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Corrected.

tls/tls_srv.c Outdated
/* TODO #309 #834 confugure on Tempesta side: "h2, http/1.1" */
if (!tls->conf->alpn_list)
return 0;
/* If TLS processig is enabled, ALPN must be configured. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/* If TLS processig is enabled, ALPN must be configured. */
/* If TLS processing is enabled, ALPN must be configured. */

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

@@ -35,8 +35,10 @@ DBG_HTTP_PARSER ?= 0
DBG_SS ?= 0
DBG_TLS ?= 0
DBG_APM ?= 0
DBG_HTTP_FRAME ?= 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bet there will be families of debug functions for HTTP2: for frames, HPACK, and what ever else. The whole group will have the same meaning to HTTP2 as DBG_HTTP_PARSER for HTTP1.1. Should we rename it as DBG_HTTP2_FRAME?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I cannot do such separation: these sets do not intersect yet; also both HTTP/1.1 and HTTP/2 protocols belong to the same HTTP domain, so there is no contradiction here. But in the nearest future (e.g. during HTTP parser implementation changing in context of HTTP/2 processing) mentioned intersections may appear, and in this case the separation for HTTP1_* and HTTP2_* may be really needed and will be made for preprocessor variables (and possibly for filenames too, e.g. http_frame.c/h, http_stream.c/h).

@@ -209,9 +210,11 @@ enum {
typedef struct {
TfwCliConn cli_conn;
TlsCtx tls;
TfwHttp2Ctx *h2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The structure name becomes misleading, now it's more than TLS connection, it also stores the HTTP2 context. And a new issue is introduced: HTTP2 context is not allocated for non-TLS HTTP2 connections (which are allowed by standard).
In the same time HTTP2 connections will have two contexts in the same time: HTTP2 and HTTP1. HTTP1 context is stored as TfwConn->TfwHttpParser. Probably we should introduce a union in TfwConn class to store 'protocol context' whatever http2 or http1. Seems like we never want both. Even is the HTTP1 connection is upgraded to HTTP2 we can easily re-init the field.

Copy link
Contributor Author

@aleksostapenko aleksostapenko Apr 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP2 context is not allocated for non-TLS HTTP2 connections (which are allowed by standard)

In result of discussion in #309 and in chat - it has been decided not to support non-TLS HTTP/2 in TempestaFW.

Probably we should introduce a union in TfwConn class to store 'protocol context' whatever http2 or http1.

Yes, agree with that. The similar approach is proposed in #309 (comment) (in Stream Priority/Dependencies). These changes is part of future PRs in context of #309 ("Request HTTP/2 -> HTTP/1.1" or more soon "Disable @seq_queue for HTTP/2"). During implementation of Framing, Scheduler and Stream States - I temporary left that part as is - for testing/debugging purposes.

static int
__tfw_http_msg_process(void *conn, TfwFsmData *data)
int
tfw_http_msg_process_generic(void *conn, TfwFsmData *data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad naming. It's not generic. It's HTTP1 processing.

Copy link
Contributor Author

@aleksostapenko aleksostapenko Apr 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the nearest future PRs (in context of #309) this function is planned for usage for HTTP/2 processing too, so I have run a little forward here. In my opinion, most part of tfw_http_msg_process_generic() is general processing, whatever HTTP/1.1 or HTTP/2 protocol (except the parsing stage only), so it is worth to try adapt it for both protocols. In any case if this idea will fail, and the separate procedures will be needed - the name will be reverted accordingly.

@@ -3930,7 +3931,9 @@ tfw_http_msg_process(void *conn, TfwFsmData *data)
if (likely(r == T_OK || r == T_POSTPONE)) {
data->skb->next = data->skb->prev = NULL;
data->trail = !next ? trail : 0;
r = __tfw_http_msg_process(conn, data);
r = TFW_CONN_TLS((TfwConn *)conn) && tfw_http2_context(conn)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like TFW_CONN_TLS((TfwConn *)conn) is extra here. HTTP2 recommends using HTTP2 over TLS (h2) but it still allows HTTP2 over TCP (h2c). Personally I don't understand why the unencrypted connections are allowed by standard, but we have to follow them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been decided not to support non-TLS HTTP/2 in TempestaFW: standard allows HTTP/2 over plain TCP, but does not force to use it.

* Tempesta FW
*
* Copyright (C) 2014 NatSys Lab. ([email protected]).
* Copyright (C) 2015-2019 Tempesta Technologies, Inc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad copy-paste. This file wasn't existed before, so only 2019 here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

* and GOAWAY frames to report the reasons of the stream or
* connection error.
*/
#define FRAME_ECODE_PROTO 0x1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Section 7 contains 14 error codes. I understand that only two are needed at this moment, but it seems that we will definitely will need all of them, let's introduce enum like TfwFrameType to store all the possible errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* Tempesta FW
*
* Copyright (C) 2014 NatSys Lab. ([email protected]).
* Copyright (C) 2015-2019 Tempesta Technologies, Inc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Bad copy-paste.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

* this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __HTTP_FRAME__
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__HTTP2_FRAME__?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file has name http_frame.h, so this will be irrelevant (also see #1233 (comment)).

HTTP2_RECV_HEADER = __HTTP2_RECV_FRAME_APP,
HTTP2_RECV_CONT,
HTTP2_RECV_DATA
} TfwFrameState;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to expose this states to other modules? Why it's not in http2_frame.c?

Copy link
Contributor Author

@aleksostapenko aleksostapenko Apr 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we need that due to necessity of correct state initialization in tfw_tls_check_alloc_h2_context() in tls.c.

* @flags - frame's flags;
*/
typedef struct {
int length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never going to be below 0, thus should be unsigned.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never going to be below 0

Currently, code in tfw_http2_recv_priority() may temporarily make length negative. If, for example, client sends a wrong length in PRIORITY frame.

Copy link
Contributor

@krizhanovsky krizhanovsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to merge, but please make the several cleanups/improvements before. It's also good to discuss (think once more) the parser design.

return tfw_http2_stream_terminate(ctx,
hdr->stream_id,
NULL,
HTTP2_ECODE_REFUSED);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line is too wide. I'd propose to use tfw_h2_ prefix instead of tfw_http2_. There is too deep nesting, probably the case code should be moved to separate function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

return 0;
}

h2 = kzalloc(sizeof(TfwHttp2Ctx), GFP_ATOMIC);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use SLAB for fixed-size allocations. Next, h2 is first class citizen for us while HTTP/1 is legacy. We also don't have any business with plain TLS, so it's likely that any TLS connection is essentially a h2 connection. I think TfwHttp2Ctx should be inherited from TfwTlsConn instead of using the pointer, so let's just allocated large piece of memory to fit TLS and h2 context.

BTW @i-rinat probably h2 context is a good place to store second checksum. In HTTP/3 all the layers must be aware about each other after all, so this can be an option (I don't like it though, but if we're out of memory on TLS handshakes, then this makes sense to use the extra memory and there is guarantee that we move to either h2 or h3 after TLS stuff, even for QUIC).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

r = __tfw_http_msg_process(conn, data);
r = TFW_CONN_TLS((TfwConn *)conn) && tfw_http2_context(conn)
? tfw_http2_frame_process(conn, data)
: tfw_http_msg_process_generic(conn, data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #309 we discussed that we should split HTTP parser in at least 2 pieces: headers and body and both the parsers will be called separately from H2 layer. How do you see the split in current code? Check H2 state in tfw_http_req_process()?

Frankly, now we have single-jump cost in our parser to enter any state and I believe we're able to make GCC, probably with some assembly help, to generate proper FSM code layout to make the large parser code faster (after all, even after the parser split, we'll have complex FSM due to many checks), so probably we'll be fine with current code if it simpler than possible split parser.

Copy link
Contributor Author

@aleksostapenko aleksostapenko May 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check H2 state in tfw_http_req_process()?

Yeah - this must be a frame type and, maybe, a stream state (since we have to track request's start/end, and this exactly matches with stream's states, as mentioned in penultimate paragraph in https://tools.ietf.org/html/rfc7540#section-8.1).

Сurrently I'm not very optimistic about parser division into separate parts: indeed, we have rather effective implementation with single-jump cost to enter any state; and with divided parser we will get costs of additional function calls (if not inlined) and necessity for additional branching to call separate parser parts (with associated costs). But in general, I am still thinking about this point.


#define CONF_HTTPS "https"
#define CONF_HTTP1 "http1"
#define CONF_HTTP2 "http2"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update etc/tempesta_fw.conf and appropriate Wiki with the HTTP/2 support. Please say (in bold) in the WIki that HTTP/2 implementation is incomplete.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

protos[order].id = TTLS_ALPN_ID_HTTP1;
protos[!order].name = TTLS_ALPN_HTTP2;
protos[!order].len = sizeof(TTLS_ALPN_HTTP2) - 1;
protos[!order].id = TTLS_ALPN_ID_HTTP2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not a good idea to enable HTTP/2 by default before we have the stable implementation - this may lead to bad user experience. I also vote for RFC compliant name like h2.

}
}

new_stream = kzalloc(sizeof(TfwStream), GFP_ATOMIC);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same allocation problem: basically we usually don't use pattern kzalloc(sizeof(....), ...) in any more or less performance crucial code - if we have fixed size allocations, then we use some kind of SLAB allocator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah - missed that. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

tfw_http2_init_stream(new_stream, id, weight);

rb_link_node(&new_stream->node, parent, new);
rb_insert_color(&new_stream->node, &sched->streams);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need priority index plus to current index for stream ID (as you said in the PR description), so we need two indexes. However, binary heap is technically an array (continuous memory location which usually gives us good spactial locality in run time - this is why I wanted binary heap in #309), and, since you already use dynamic memory allocator, all your TfwStream instances reside somewhere in memory and it's not wise to use additional array just for heap index. It's better to introduce additional node entries in TfwStream to build the second index.

If you fix the kzalloc() above, then SLAB/SLOB/SLUB already cares about spacial locality. The question is: do we expect to see more frequently frames from the same TCP connection streams or from streams as they first appeared (to fit the internal SLAB allocation pattern)? I think the first one, but I won't bet that there is so strong spacial locality in access pattern to streams from the same heap/rb-tree. Moreover, if we use binary heap, as I proposed, on top of an array, we'll have to manager erased items, i.e. move stored items and this is basically slower than SLAB's bitmasks.

All it all, I think RB tree is a good enough decision here since there is no confidence in access pattern. I write the comment for #1196 and will leave link there to the comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I'll think yet further about building a dependency/priority tree.

tfw_http2_init_stream(new_stream, id, weight);

rb_link_node(&new_stream->node, parent, new);
rb_insert_color(&new_stream->node, &sched->streams);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need priority index plus to current index for stream ID (as you said in the PR description), so we need two indexes. However, binary heap is technically an array (continuous memory location which usually gives us good spactial locality in run time - this is why I wanted binary heap in #309), and, since you already use dynamic memory allocator, all your TfwStream instances reside somewhere in memory and it's not wise to use additional array just for heap index. It's better to introduce additional node entries in TfwStream to build the second index.

If you fix the kzalloc() above, then SLAB/SLOB/SLUB already cares about spacial locality. The question is: do we expect to see more frequently frames from the same TCP connection streams or from streams as they first appeared (to fit the internal SLAB allocation pattern)? I think the first one, but I won't bet that there is so strong spacial locality in access pattern to streams from the same heap/rb-tree. Moreover, if we use binary heap, as I proposed, on top of an array, we'll have to manager erased items, i.e. move stored items and this is basically slower than SLAB's bitmasks.

All it all, I think RB tree is a good enough decision here since there is no confidence in access pattern. I write the comment for #1196 and will leave link there to the comment.

@krizhanovsky krizhanovsky mentioned this pull request May 12, 2019
4 tasks
1. "http2 -> h2" renaming for functions and structures;
2. SLAB usage for allocations.
1. Make 'TfwH2Conn' (with HTTP/2 context) inherited from 'TfwTlsConn'.
2. Avoid default enabling of HTTP/2 protocol.
@aleksostapenko aleksostapenko merged commit aee18fe into master May 16, 2019
@aleksostapenko aleksostapenko deleted the ao-309-framing branch May 16, 2019 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants