From d1229eeca48ef349a8a9fc0748bc01789bdbce91 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Fri, 2 Aug 2024 12:44:20 -0700 Subject: [PATCH] lib: rewrite AsyncLocalStorage without async_hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/48528 Reviewed-By: Matteo Collina Reviewed-By: Yagiz Nizipli Reviewed-By: James M Snell Reviewed-By: Benjamin Gruenbaum Reviewed-By: Rafael Gonzaga Reviewed-By: Chengzhong Wu Reviewed-By: Santiago Gimeno Reviewed-By: Gerhard Stöbich --- ...local-storage-getstore-nested-resources.js | 10 +- ...async-local-storage-getstore-nested-run.js | 6 +- doc/api/cli.md | 16 +++ lib/async_hooks.js | 119 +++--------------- lib/internal/async_context_frame.js | 50 ++++++++ .../async_local_storage/async_hooks.js | 117 +++++++++++++++++ lib/internal/async_local_storage/native.js | 47 +++++++ lib/internal/process/promises.js | 6 + lib/internal/process/task_queues.js | 11 ++ lib/internal/timers.js | 15 +++ node.gyp | 2 + src/api/async_resource.cc | 44 +++++-- src/api/callback.cc | 68 +++++++--- src/async_context_frame.cc | 89 +++++++++++++ src/async_context_frame.h | 33 +++++ src/async_wrap-inl.h | 3 + src/async_wrap.cc | 22 +++- src/async_wrap.h | 4 + src/env-inl.h | 20 +++ src/env.h | 13 +- src/node_api.cc | 22 ++-- src/node_binding.cc | 1 + src/node_internals.h | 24 +++- src/node_options.cc | 4 + src/node_options.h | 1 + .../errors/async_error_nexttick_main.snapshot | 2 +- test/parallel/test-async-context-frame.mjs | 59 +++++++++ ...-async-local-storage-exit-does-not-leak.js | 21 ++-- test/parallel/test-bootstrap-modules.js | 2 + 29 files changed, 658 insertions(+), 173 deletions(-) create mode 100644 lib/internal/async_context_frame.js create mode 100644 lib/internal/async_local_storage/async_hooks.js create mode 100644 lib/internal/async_local_storage/native.js create mode 100644 src/async_context_frame.cc create mode 100644 src/async_context_frame.h create mode 100644 test/parallel/test-async-context-frame.mjs diff --git a/benchmark/async_hooks/async-local-storage-getstore-nested-resources.js b/benchmark/async_hooks/async-local-storage-getstore-nested-resources.js index 3474e801e01..65faa73440a 100644 --- a/benchmark/async_hooks/async-local-storage-getstore-nested-resources.js +++ b/benchmark/async_hooks/async-local-storage-getstore-nested-resources.js @@ -38,9 +38,11 @@ function runInAsyncScopes(resourceCount, cb, i = 0) { function main({ n, resourceCount }) { const store = new AsyncLocalStorage(); - runInAsyncScopes(resourceCount, () => { - bench.start(); - runBenchmark(store, n); - bench.end(n); + store.run({}, () => { + runInAsyncScopes(resourceCount, () => { + bench.start(); + runBenchmark(store, n); + bench.end(n); + }); }); } diff --git a/benchmark/async_hooks/async-local-storage-getstore-nested-run.js b/benchmark/async_hooks/async-local-storage-getstore-nested-run.js index 5f8948f62eb..074a44b1ce2 100644 --- a/benchmark/async_hooks/async-local-storage-getstore-nested-run.js +++ b/benchmark/async_hooks/async-local-storage-getstore-nested-run.js @@ -14,7 +14,7 @@ const { AsyncLocalStorage } = require('async_hooks'); * - AsyncLocalStorage1.getStore() */ const bench = common.createBenchmark(main, { - sotrageCount: [1, 10, 100], + storageCount: [1, 10, 100], n: [1e4], }); @@ -34,8 +34,8 @@ function runStores(stores, value, cb, idx = 0) { } } -function main({ n, sotrageCount }) { - const stores = new Array(sotrageCount).fill(0).map(() => new AsyncLocalStorage()); +function main({ n, storageCount }) { + const stores = new Array(storageCount).fill(0).map(() => new AsyncLocalStorage()); const contextValue = {}; runStores(stores, contextValue, () => { diff --git a/doc/api/cli.md b/doc/api/cli.md index 7111bf36817..f61824f1087 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -886,6 +886,21 @@ and `"` are usable. It is possible to run code containing inline types by passing [`--experimental-strip-types`][]. +### `--experimental-async-context-frame` + + + +> Stability: 1 - Experimental + +Enables the use of AsyncLocalStorage backed by AsyncContextFrame rather than +the default implementation which relies on async\_hooks. This new model is +implemented very differently and so could have differences in how context data +flows within the application. As such, it is presently recommended to be sure +your application behaviour is unaffected by this change before using it in +production. + ### `--experimental-default-type=type`