Skip to content

Commit

Permalink
async_hooks: use resource stack for AsyncLocalStorage run
Browse files Browse the repository at this point in the history
  • Loading branch information
Qard committed Aug 26, 2021
1 parent 95834d1 commit 9fd9740
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 16 deletions.
21 changes: 21 additions & 0 deletions benchmark/async_hooks/async-local-storage-run.js
@@ -0,0 +1,21 @@
'use strict';
const common = require('../common.js');
const { AsyncLocalStorage } = require('async_hooks');

const bench = common.createBenchmark(main, {
n: [1e7]
});

async function run(store, n) {
for (let i = 0; i < n; i++) {
await new Promise((resolve) => store.run(i, resolve));
}
}

function main({ n }) {
const store = new AsyncLocalStorage();
bench.start();
run(store, n).then(() => {
bench.end(n);
});
}
20 changes: 12 additions & 8 deletions lib/async_hooks.js
Expand Up @@ -263,11 +263,11 @@ const storageHook = createHook({
}
});

const defaultAlsResourceOpts = { requireManualDestroy: true };
class AsyncLocalStorage {
constructor() {
this.kResourceStore = Symbol('kResourceStore');
this.enabled = false;
this._stack = [];
}

disable() {
Expand Down Expand Up @@ -309,14 +309,18 @@ class AsyncLocalStorage {
if (ObjectIs(store, this.getStore())) {
return ReflectApply(callback, null, args);
}
const resource = new AsyncResource('AsyncLocalStorage',
defaultAlsResourceOpts);
// Calling emitDestroy before runInAsyncScope avoids a try/finally
// It is ok because emitDestroy only schedules calling the hook
return resource.emitDestroy().runInAsyncScope(() => {
this.enterWith(store);

this._enable();
this._stack.push(this.getStore());

const resource = executionAsyncResource();
resource[this.kResourceStore] = store;

try {
return ReflectApply(callback, null, args);
});
} finally {
resource[this.kResourceStore] = this._stack.pop();
}
}

exit(callback, ...args) {
Expand Down
12 changes: 4 additions & 8 deletions test/async-hooks/test-async-local-storage-run-resource.js
Expand Up @@ -7,24 +7,20 @@ const {
} = require('async_hooks');

const asyncLocalStorage = new AsyncLocalStorage();

const outerResource = executionAsyncResource();
assert.strictEqual(asyncLocalStorage.getStore(), undefined);

const store = new Map();
asyncLocalStorage.run(store, () => {
assert.strictEqual(asyncLocalStorage.getStore(), store);
const innerResource = executionAsyncResource();
assert.notStrictEqual(innerResource, outerResource);
asyncLocalStorage.run(store, () => {
assert.strictEqual(asyncLocalStorage.getStore(), store);
assert.strictEqual(executionAsyncResource(), innerResource);
const otherStore = new Map();
asyncLocalStorage.run(otherStore, () => {
assert.strictEqual(asyncLocalStorage.getStore(), otherStore);
assert.notStrictEqual(executionAsyncResource(), innerResource);
assert.notStrictEqual(executionAsyncResource(), outerResource);
});
assert.strictEqual(asyncLocalStorage.getStore(), store);
});
assert.strictEqual(asyncLocalStorage.getStore(), store);
});

assert.strictEqual(executionAsyncResource(), outerResource);
assert.strictEqual(asyncLocalStorage.getStore(), undefined);

0 comments on commit 9fd9740

Please sign in to comment.