From 167660beb8f9a66b79b7cae11bfb784963b8f727 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 3 Jun 2016 01:32:56 -0400 Subject: [PATCH 1/7] uv_link_t: initial --- 000-index.md | 1 + xxx-uv_link_t.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 xxx-uv_link_t.md diff --git a/000-index.md b/000-index.md index c5cecb2..4f20f69 100644 --- a/000-index.md +++ b/000-index.md @@ -2,3 +2,4 @@ * [Public C++ Streams](001-public-stream-base.md) * [ES6 Module Interoperability](002-es6-modules.md) +* [Port core to uv_link_t](xxx-uv_link_t.md) diff --git a/xxx-uv_link_t.md b/xxx-uv_link_t.md new file mode 100644 index 0000000..b8faf37 --- /dev/null +++ b/xxx-uv_link_t.md @@ -0,0 +1,67 @@ +| Title | Port core to uv_link_t | +|--------|-----------------------------| +| Author | @indutny | +| Status | DRAFT | +| Date | 2016-06-03 | + +## 1. Proposal + +I propose to replace `StreamBase` with [`uv_link_t`][0], and port existing +classes that inherit from `StreamBase`. + +## 2. Current state of C++ Streams in Node + +The fast HTTP and TLS protocol implementation in Node core depends on so called +`StreamBase` C++ class. This class is an analog of JavaScript streams in C++. +The main ideas behind `StreamBase` is to: + +1. Avoid unnecessary memory allocations by reading data directly into buffer + from which it will be synchronously parsed +2. Avoid calling JavaScript unless absolutely necessary + +However, this API has lots of dependencies on the core internals, and thus +can't be used outside of it. + +## 3. uv_link_t + +From [`uv_link_t`][0] readme: + + Chainable libuv streams. + + It is quite easy to write a TCP server/client in [libuv][0]. Writing HTTP + server/client is a bit harder. Writing HTTP server/client on top of TLS + server could be unwieldy. + + `uv_link_t` aims to solve complexity problem that quickly escalates once + using multiple layers of protocols in [libuv][0] by providing a way to + implement protocols separately and chain them together in easy and + high-performant way using very narrow interfaces. + +Given that [`uv_link_t`][0] depends only on [libuv][1], it is very easy to +envision how it will be used in Node.js addons. Even core modules will no longer +be required to be distributed with core, since they could be built without core +dependencies. + +## 4. Proof-of-Concept + +Several modules were created as a Proof-of-Concept [`uv_link_t`][0] +implementations (which possibly could be modified to fit into core): + +* [`uv_ssl_t`][2] +* [`uv_http_t`][3] + +They can be combined together quite trivially as demonstrated in +[file-shooter][4]. + +## 5. Further Thoughts + +Another abstraction level could be added for multiplexing [`uv_link_t`][0]s to +provide a common C interface for http2 and http1.1. This will help us bring +a http2 implementation into the core while reusing as much of the existing code +as possible. + +[0]: https://github.com/indutny/uv_link_t +[1]: https://github.com/libuv/libuv +[2]: https://github.com/indutny/uv_ssl_t +[3]: https://github.com/indutny/uv_http_t +[4]: https://github.com/indutny/file-shooter From 561ba80b553b235018504fb38cf452148b8c54a1 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 3 Jun 2016 14:19:21 -0400 Subject: [PATCH 2/7] fixes --- xxx-uv_link_t.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xxx-uv_link_t.md b/xxx-uv_link_t.md index b8faf37..42249f4 100644 --- a/xxx-uv_link_t.md +++ b/xxx-uv_link_t.md @@ -13,7 +13,7 @@ classes that inherit from `StreamBase`. The fast HTTP and TLS protocol implementation in Node core depends on so called `StreamBase` C++ class. This class is an analog of JavaScript streams in C++. -The main ideas behind `StreamBase` is to: +The main ideas behind `StreamBase` are to: 1. Avoid unnecessary memory allocations by reading data directly into buffer from which it will be synchronously parsed @@ -28,12 +28,12 @@ From [`uv_link_t`][0] readme: Chainable libuv streams. - It is quite easy to write a TCP server/client in [libuv][0]. Writing HTTP + It is quite easy to write a TCP server/client in [libuv][1]. Writing HTTP server/client is a bit harder. Writing HTTP server/client on top of TLS server could be unwieldy. `uv_link_t` aims to solve complexity problem that quickly escalates once - using multiple layers of protocols in [libuv][0] by providing a way to + using multiple layers of protocols in [libuv][1] by providing a way to implement protocols separately and chain them together in easy and high-performant way using very narrow interfaces. @@ -57,8 +57,8 @@ They can be combined together quite trivially as demonstrated in Another abstraction level could be added for multiplexing [`uv_link_t`][0]s to provide a common C interface for http2 and http1.1. This will help us bring -a http2 implementation into the core while reusing as much of the existing code -as possible. +a http2 implementation into the core while reusing as much as possible of the +existing code. [0]: https://github.com/indutny/uv_link_t [1]: https://github.com/libuv/libuv From 50199ab283031444930330839a4635e1249003a3 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 3 Jun 2016 14:33:57 -0400 Subject: [PATCH 3/7] add note about observability --- xxx-uv_link_t.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xxx-uv_link_t.md b/xxx-uv_link_t.md index 42249f4..afc4ade 100644 --- a/xxx-uv_link_t.md +++ b/xxx-uv_link_t.md @@ -42,6 +42,12 @@ envision how it will be used in Node.js addons. Even core modules will no longer be required to be distributed with core, since they could be built without core dependencies. +Additionally, with the `uv_link_observer_t` (which is a part of [`uv_link_t`][0] +distribution), all of the reads that right now happen internally within the +`StreamBase` will be **observable**. This means that JavaScript user code will +still be able to listen for `data` events on the `net.Socket` that was consumed +by some `uv_link_t` stream. + ## 4. Proof-of-Concept Several modules were created as a Proof-of-Concept [`uv_link_t`][0] From d4ac1d563d0b5709531f47892875e90f38459d26 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 3 Jun 2016 14:57:53 -0400 Subject: [PATCH 4/7] fixes --- xxx-uv_link_t.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xxx-uv_link_t.md b/xxx-uv_link_t.md index afc4ade..d36644d 100644 --- a/xxx-uv_link_t.md +++ b/xxx-uv_link_t.md @@ -38,9 +38,8 @@ From [`uv_link_t`][0] readme: high-performant way using very narrow interfaces. Given that [`uv_link_t`][0] depends only on [libuv][1], it is very easy to -envision how it will be used in Node.js addons. Even core modules will no longer -be required to be distributed with core, since they could be built without core -dependencies. +envision how it will be used in Node.js addons. Even core modules will could +be reimplemented on a user level without a need to patch the core itself. Additionally, with the `uv_link_observer_t` (which is a part of [`uv_link_t`][0] distribution), all of the reads that right now happen internally within the From 2dd1e26d735b4c2007101bd39db944b1637d5191 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 3 Jun 2016 20:07:25 -0400 Subject: [PATCH 5/7] fix typo --- xxx-uv_link_t.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xxx-uv_link_t.md b/xxx-uv_link_t.md index d36644d..4e7a883 100644 --- a/xxx-uv_link_t.md +++ b/xxx-uv_link_t.md @@ -38,7 +38,7 @@ From [`uv_link_t`][0] readme: high-performant way using very narrow interfaces. Given that [`uv_link_t`][0] depends only on [libuv][1], it is very easy to -envision how it will be used in Node.js addons. Even core modules will could +envision how it will be used in Node.js addons. Even core modules could be reimplemented on a user level without a need to patch the core itself. Additionally, with the `uv_link_observer_t` (which is a part of [`uv_link_t`][0] From 8080c8fba0b6ddd45790d54b4be26ba727269dd7 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Mon, 6 Jun 2016 12:26:34 -0400 Subject: [PATCH 6/7] fix --- xxx-uv_link_t.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/xxx-uv_link_t.md b/xxx-uv_link_t.md index 4e7a883..d47ceb1 100644 --- a/xxx-uv_link_t.md +++ b/xxx-uv_link_t.md @@ -12,7 +12,8 @@ classes that inherit from `StreamBase`. ## 2. Current state of C++ Streams in Node The fast HTTP and TLS protocol implementation in Node core depends on so called -`StreamBase` C++ class. This class is an analog of JavaScript streams in C++. +`StreamBase` C++ class and auxiliary `StreamReq` and `StreamResources` classes. +This class is an analog of JavaScript streams in C++. The main ideas behind `StreamBase` are to: 1. Avoid unnecessary memory allocations by reading data directly into buffer @@ -34,7 +35,7 @@ From [`uv_link_t`][0] readme: `uv_link_t` aims to solve complexity problem that quickly escalates once using multiple layers of protocols in [libuv][1] by providing a way to - implement protocols separately and chain them together in easy and + implement protocols separately and chain them together in an easy and high-performant way using very narrow interfaces. Given that [`uv_link_t`][0] depends only on [libuv][1], it is very easy to From 6c683d0edd6eaeb969973b5f8b6dcad8c1f066ab Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Thu, 16 Jun 2016 13:51:02 -0400 Subject: [PATCH 7/7] add description --- xxx-uv_link_t.md | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/xxx-uv_link_t.md b/xxx-uv_link_t.md index d47ceb1..5321f53 100644 --- a/xxx-uv_link_t.md +++ b/xxx-uv_link_t.md @@ -48,6 +48,86 @@ distribution), all of the reads that right now happen internally within the still be able to listen for `data` events on the `net.Socket` that was consumed by some `uv_link_t` stream. +## 3.1. uv_link_t technical description + +_(NOTE: chain is built from links)_ + +_(NOTE: many of these API methods have return values, check them!)_ + +First, a `uv_stream_t*` instance needs to be picked. It will act as a source +link in a chain: +```c +uv_stream_t* stream = ...; + +uv_link_source_t source; + +uv_link_source_init(uv_default_loop(), &source, stream); +``` + +A chain can be formed with `&source` and any other `uv_link_t` instance: +```c +uv_link_t link; + +static uv_link_methods_t methods = { + .read_start = read_start_impl, + .read_stop = read_stop_impl, + .write = write_impl, + .try_write = try_write_impl, + .shutdown = shutdown_impl, + .close = close_impl, + + /* These will be used only when chaining two links together */ + + .alloc_cb_override = alloc_cb_impl, + .read_cb_override = read_cb_impl +}; + +uv_link_init(&link, &methods); + +/* Just like in libuv */ +link.alloc_cb = my_alloc_cb; +link.read_cb = my_read_cb; + +/* Creating a chain here */ +uv_link_chain(&source, &link); + +uv_link_read_start(&link); +``` + +Now comes a funny part, any of these method implementations may hook up into +the parent link in a chain to perform their actions: + +```c +static int shutdown_impl(uv_link_t* link, + uv_link_t* source, + uv_link_shutdown_cb cb, + void* arg) { + fprintf(stderr, "this will be printed\n"); + return uv_link_propagate_shutdown(link->parent, source, cb, arg); +} +``` + +## 3.2. How things are going to be hooked up into the core + +TCP sockets, IPC pipes, and possibly TTYs will be a base elements of every +chain, backed up by the `uv_link_source_t`. + +HTTP, TLS, WebSockets(?) will be custom `uv_link_methods_t`, so that the links +could be created for them and chained together with the `uv_link_source_t`. + +The chaining process will happen in JavaScript through the method that will +take `v8:External` from the both `uv_link_t` instances, and run `uv_link_chain` +on them. + +User `uv_link_methods_t` implementations will work in pretty much the same way, +bringing consistency to the C++ streams implementation. + +## 3.3. Observability + +`uv_link_observer_t` may be inserted between any two `uv_link_t`s to observe +the incoming data that flows between them. This is a huge difference for TLS, +where right now it is not possible to read any raw incoming bytes. + ## 4. Proof-of-Concept Several modules were created as a Proof-of-Concept [`uv_link_t`][0]