lib: improve async_context_frame structure

PR-URL: https://github.com/nodejs/node/pull/54239
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
Stephen Belanger 2024-08-09 12:44:42 -07:00 committed by GitHub
parent 88760f1c30
commit 7366808b85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 46 additions and 21 deletions

View File

@ -894,8 +894,8 @@ added: REPLACEME
> 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
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
@ -3472,6 +3472,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
[`--print`]: #-p---print-script
[`--redirect-warnings`]: #--redirect-warningsfile
[`--require`]: #-r---require-module
[`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage
[`Buffer`]: buffer.md#class-buffer
[`CRYPTO_secure_malloc_init`]: https://www.openssl.org/docs/man3.0/man3/CRYPTO_secure_malloc_init.html
[`NODE_OPTIONS`]: #node_optionsoptions

View File

@ -280,7 +280,7 @@ module.exports = {
// Public API
get AsyncLocalStorage() {
return AsyncContextFrame.enabled ?
require('internal/async_local_storage/native') :
require('internal/async_local_storage/async_context_frame') :
require('internal/async_local_storage/async_hooks');
},
createHook,

View File

@ -1,5 +1,9 @@
'use strict';
const {
ObjectSetPrototypeOf,
} = primordials;
const {
getContinuationPreservedEmbedderData,
setContinuationPreservedEmbedderData,
@ -7,28 +11,17 @@ const {
let enabled_;
class AsyncContextFrame extends Map {
constructor(store, data) {
super(AsyncContextFrame.current());
this.set(store, data);
}
class ActiveAsyncContextFrame {
static get enabled() {
enabled_ ??= require('internal/options')
.getOptionValue('--experimental-async-context-frame');
return enabled_;
return true;
}
static current() {
if (this.enabled) {
return getContinuationPreservedEmbedderData();
}
return getContinuationPreservedEmbedderData();
}
static set(frame) {
if (this.enabled) {
setContinuationPreservedEmbedderData(frame);
}
setContinuationPreservedEmbedderData(frame);
}
static exchange(frame) {
@ -41,6 +34,37 @@ class AsyncContextFrame extends Map {
const frame = this.current();
frame?.disable(store);
}
}
function checkEnabled() {
const enabled = require('internal/options')
.getOptionValue('--experimental-async-context-frame');
// If enabled, swap to active prototype so we don't need to check status
// on every interaction with the async context frame.
if (enabled) {
// eslint-disable-next-line no-use-before-define
ObjectSetPrototypeOf(AsyncContextFrame, ActiveAsyncContextFrame);
}
return enabled;
}
class AsyncContextFrame extends Map {
constructor(store, data) {
super(AsyncContextFrame.current());
this.set(store, data);
}
static get enabled() {
enabled_ ??= checkEnabled();
return enabled_;
}
static current() {}
static set(frame) {}
static exchange(frame) {}
static disable(store) {}
disable(store) {
this.delete(store);

View File

@ -44,7 +44,7 @@ const { AsyncResource } = require('async_hooks');
const AsyncContextFrame = require('internal/async_context_frame');
const async_context_frame = Symbol('asyncContextFrame');
const async_context_frame = Symbol('kAsyncContextFrame');
// *Must* match Environment::TickInfo::Fields in src/env.h.
const kHasTickScheduled = 0;

View File

@ -124,7 +124,7 @@ let debug = require('internal/util/debuglog').debuglog('timer', (fn) => {
const AsyncContextFrame = require('internal/async_context_frame');
const async_context_frame = Symbol('asyncContextFrame');
const async_context_frame = Symbol('kAsyncContextFrame');
// *Must* match Environment::ImmediateInfo::Fields in src/env.h.
const kCount = 0;

View File

@ -27,8 +27,8 @@ AsyncResource::AsyncResource(Isolate* isolate,
AsyncResource::~AsyncResource() {
CHECK_NOT_NULL(env_);
env_->RemoveAsyncResourceContextFrame(reinterpret_cast<std::uintptr_t>(this));
EmitAsyncDestroy(env_, async_context_);
env_->RemoveAsyncResourceContextFrame(reinterpret_cast<std::uintptr_t>(this));
}
MaybeLocal<Value> AsyncResource::MakeCallback(Local<Function> callback,