@saber-usa/node-common 1.7.18-alpha.1 → 1.7.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/wasmProp/index.js +10 -10
- package/src/wasmProp/primitives.js +295 -295
- package/src/wasmProp/runtime.js +147 -147
- package/src/wasmProp/wasmAstro.js +251 -251
package/src/wasmProp/runtime.js
CHANGED
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
import {createSingleThreadRuntime, BulkPropagator} from "satellite.js";
|
|
2
|
-
|
|
3
|
-
// Module-local state. In Node, ES module instances are per Realm/per worker
|
|
4
|
-
// thread, so this state is naturally per-thread when consumed inside
|
|
5
|
-
// `worker_threads` (e.g. node-pub-sub's workerpool workers).
|
|
6
|
-
//
|
|
7
|
-
// See docs/BULK_PROPAGATION.md sections 6, 7, and 8 for the consumer model,
|
|
8
|
-
// lifecycle, and registry design.
|
|
9
|
-
let runtimePromise = null;
|
|
10
|
-
let registry = new Map();
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Lazily creates (or returns) the per-thread WASM runtime.
|
|
14
|
-
*
|
|
15
|
-
* On first call within a thread, triggers `createSingleThreadRuntime()`
|
|
16
|
-
* (the v7 successor to the blog's `createWasmModule()`) and caches the
|
|
17
|
-
* resulting promise. All subsequent callers in that thread reuse it.
|
|
18
|
-
*
|
|
19
|
-
* Safe to await concurrently: every caller awaits the same in-flight
|
|
20
|
-
* promise, so only one WASM compile + instantiate ever happens.
|
|
21
|
-
*
|
|
22
|
-
* @return {Promise<import("satellite.js").SingleThreadRuntime>}
|
|
23
|
-
*/
|
|
24
|
-
const getBulkRuntime = () => {
|
|
25
|
-
if (runtimePromise === null) {
|
|
26
|
-
runtimePromise = createSingleThreadRuntime();
|
|
27
|
-
}
|
|
28
|
-
return runtimePromise;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Eager bootstrap. Equivalent to `await getBulkRuntime()` but named for the
|
|
33
|
-
* explicit warm-up call site (e.g. top of `dedicated_worker.js`).
|
|
34
|
-
*
|
|
35
|
-
* @return {Promise<import("satellite.js").SingleThreadRuntime>}
|
|
36
|
-
*/
|
|
37
|
-
const initBulkRuntime = () => getBulkRuntime();
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Returns true if the runtime has been requested in this thread (regardless
|
|
41
|
-
* of whether it has finished initializing). Used by tests and by the
|
|
42
|
-
* disposal path to decide whether dispose work is necessary.
|
|
43
|
-
*
|
|
44
|
-
* @return {boolean}
|
|
45
|
-
*/
|
|
46
|
-
const isBulkRuntimeInitialized = () => runtimePromise !== null;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Acquires (or lazily constructs) the per-thread, per-pipeline singleton
|
|
50
|
-
* `BulkPropagator` for the given pipeline key.
|
|
51
|
-
*
|
|
52
|
-
* Reuse rules:
|
|
53
|
-
* - The same instance is returned on every call with the same `key`.
|
|
54
|
-
* - If the caller's `satRecsCount` or `datesCount` exceed the current
|
|
55
|
-
* allocation, the propagator's own `setSatRecs` / `setDates` will perform
|
|
56
|
-
* a single `free` + `malloc` grow-realloc internally on the next set.
|
|
57
|
-
* The initial allocation here is sized to the first caller's request, so
|
|
58
|
-
* "warm" subsequent calls of the same shape pay zero allocation cost.
|
|
59
|
-
*
|
|
60
|
-
* Caller responsibilities:
|
|
61
|
-
* - `setSatRecs`, `setDates`, then `run()` between `acquire` and using
|
|
62
|
-
* results. Within a single thread these are synchronous so no other
|
|
63
|
-
* pipeline consumer can interleave (per docs/BULK_PROPAGATION.md §9).
|
|
64
|
-
* - **Do not call `dispose()` on the returned propagator.** Lifecycle is
|
|
65
|
-
* owned by the registry; `disposeBulkRuntime()` is the only sanctioned
|
|
66
|
-
* teardown path.
|
|
67
|
-
*
|
|
68
|
-
* @param {Object} params
|
|
69
|
-
* @param {import("satellite.js").SingleThreadRuntime} params.runtime
|
|
70
|
-
* @param {string} params.key Pipeline signature, e.g. `"eci"`.
|
|
71
|
-
* @param {() => readonly any[]} params.makeCalculators Factory invoked once
|
|
72
|
-
* per (key, thread) to build fresh calculator instances. A factory is
|
|
73
|
-
* required because calculator instances are stateful and bound to a
|
|
74
|
-
* propagator at construction time; they cannot be shared across keys.
|
|
75
|
-
* @param {number} params.satRecsCount Initial satellite-record allocation
|
|
76
|
-
* hint. Used only on first construction for this key in this thread.
|
|
77
|
-
* @param {number} params.datesCount Initial dates allocation hint. Same
|
|
78
|
-
* first-call-only semantics.
|
|
79
|
-
* @return {import("satellite.js").BulkPropagator<any, any>}
|
|
80
|
-
*/
|
|
81
|
-
const getOrCreateBulkPropagator = ({
|
|
82
|
-
runtime,
|
|
83
|
-
key,
|
|
84
|
-
makeCalculators,
|
|
85
|
-
satRecsCount,
|
|
86
|
-
datesCount,
|
|
87
|
-
}) => {
|
|
88
|
-
const cached = registry.get(key);
|
|
89
|
-
if (cached) {
|
|
90
|
-
return cached;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const propagator = new BulkPropagator({
|
|
94
|
-
runtime,
|
|
95
|
-
calculators: makeCalculators(),
|
|
96
|
-
satRecsCount: Math.max(1, satRecsCount),
|
|
97
|
-
datesCount: Math.max(1, datesCount),
|
|
98
|
-
});
|
|
99
|
-
registry.set(key, propagator);
|
|
100
|
-
return propagator;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Releases all WASM memory owned by this thread: every registry-held
|
|
105
|
-
* `BulkPropagator` is disposed and the runtime itself is torn down.
|
|
106
|
-
*
|
|
107
|
-
* Idempotent: safe to call when nothing was ever initialized. After this
|
|
108
|
-
* returns, the next `getBulkRuntime()` will lazily re-initialize from
|
|
109
|
-
* scratch.
|
|
110
|
-
*/
|
|
111
|
-
const disposeBulkRuntime = async () => {
|
|
112
|
-
for (const propagator of registry.values()) {
|
|
113
|
-
try {
|
|
114
|
-
propagator.dispose();
|
|
115
|
-
} catch (e) {
|
|
116
|
-
// Disposal must never throw out of teardown; we surface the
|
|
117
|
-
// failure to stderr but continue cleaning up the rest of the
|
|
118
|
-
// registry to minimize the leak surface.
|
|
119
|
-
console.error("disposeBulkRuntime: failed to dispose propagator", e);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
registry = new Map();
|
|
123
|
-
|
|
124
|
-
if (runtimePromise !== null) {
|
|
125
|
-
const pending = runtimePromise;
|
|
126
|
-
runtimePromise = null;
|
|
127
|
-
try {
|
|
128
|
-
const runtime = await pending;
|
|
129
|
-
runtime.dispose();
|
|
130
|
-
} catch (e) {
|
|
131
|
-
// Emscripten's `_exit_runtime` (with EXIT_RUNTIME=1) signals clean
|
|
132
|
-
// shutdown by throwing an `ExitStatus` object with `status === 0`.
|
|
133
|
-
// That is the documented success path, not a failure to log.
|
|
134
|
-
if (e?.name !== "ExitStatus" || e?.status !== 0) {
|
|
135
|
-
console.error("disposeBulkRuntime: failed to dispose runtime", e);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
export {
|
|
142
|
-
getBulkRuntime,
|
|
143
|
-
initBulkRuntime,
|
|
144
|
-
isBulkRuntimeInitialized,
|
|
145
|
-
getOrCreateBulkPropagator,
|
|
146
|
-
disposeBulkRuntime,
|
|
147
|
-
};
|
|
1
|
+
import {createSingleThreadRuntime, BulkPropagator} from "satellite.js";
|
|
2
|
+
|
|
3
|
+
// Module-local state. In Node, ES module instances are per Realm/per worker
|
|
4
|
+
// thread, so this state is naturally per-thread when consumed inside
|
|
5
|
+
// `worker_threads` (e.g. node-pub-sub's workerpool workers).
|
|
6
|
+
//
|
|
7
|
+
// See docs/BULK_PROPAGATION.md sections 6, 7, and 8 for the consumer model,
|
|
8
|
+
// lifecycle, and registry design.
|
|
9
|
+
let runtimePromise = null;
|
|
10
|
+
let registry = new Map();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Lazily creates (or returns) the per-thread WASM runtime.
|
|
14
|
+
*
|
|
15
|
+
* On first call within a thread, triggers `createSingleThreadRuntime()`
|
|
16
|
+
* (the v7 successor to the blog's `createWasmModule()`) and caches the
|
|
17
|
+
* resulting promise. All subsequent callers in that thread reuse it.
|
|
18
|
+
*
|
|
19
|
+
* Safe to await concurrently: every caller awaits the same in-flight
|
|
20
|
+
* promise, so only one WASM compile + instantiate ever happens.
|
|
21
|
+
*
|
|
22
|
+
* @return {Promise<import("satellite.js").SingleThreadRuntime>}
|
|
23
|
+
*/
|
|
24
|
+
const getBulkRuntime = () => {
|
|
25
|
+
if (runtimePromise === null) {
|
|
26
|
+
runtimePromise = createSingleThreadRuntime();
|
|
27
|
+
}
|
|
28
|
+
return runtimePromise;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Eager bootstrap. Equivalent to `await getBulkRuntime()` but named for the
|
|
33
|
+
* explicit warm-up call site (e.g. top of `dedicated_worker.js`).
|
|
34
|
+
*
|
|
35
|
+
* @return {Promise<import("satellite.js").SingleThreadRuntime>}
|
|
36
|
+
*/
|
|
37
|
+
const initBulkRuntime = () => getBulkRuntime();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns true if the runtime has been requested in this thread (regardless
|
|
41
|
+
* of whether it has finished initializing). Used by tests and by the
|
|
42
|
+
* disposal path to decide whether dispose work is necessary.
|
|
43
|
+
*
|
|
44
|
+
* @return {boolean}
|
|
45
|
+
*/
|
|
46
|
+
const isBulkRuntimeInitialized = () => runtimePromise !== null;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Acquires (or lazily constructs) the per-thread, per-pipeline singleton
|
|
50
|
+
* `BulkPropagator` for the given pipeline key.
|
|
51
|
+
*
|
|
52
|
+
* Reuse rules:
|
|
53
|
+
* - The same instance is returned on every call with the same `key`.
|
|
54
|
+
* - If the caller's `satRecsCount` or `datesCount` exceed the current
|
|
55
|
+
* allocation, the propagator's own `setSatRecs` / `setDates` will perform
|
|
56
|
+
* a single `free` + `malloc` grow-realloc internally on the next set.
|
|
57
|
+
* The initial allocation here is sized to the first caller's request, so
|
|
58
|
+
* "warm" subsequent calls of the same shape pay zero allocation cost.
|
|
59
|
+
*
|
|
60
|
+
* Caller responsibilities:
|
|
61
|
+
* - `setSatRecs`, `setDates`, then `run()` between `acquire` and using
|
|
62
|
+
* results. Within a single thread these are synchronous so no other
|
|
63
|
+
* pipeline consumer can interleave (per docs/BULK_PROPAGATION.md §9).
|
|
64
|
+
* - **Do not call `dispose()` on the returned propagator.** Lifecycle is
|
|
65
|
+
* owned by the registry; `disposeBulkRuntime()` is the only sanctioned
|
|
66
|
+
* teardown path.
|
|
67
|
+
*
|
|
68
|
+
* @param {Object} params
|
|
69
|
+
* @param {import("satellite.js").SingleThreadRuntime} params.runtime
|
|
70
|
+
* @param {string} params.key Pipeline signature, e.g. `"eci"`.
|
|
71
|
+
* @param {() => readonly any[]} params.makeCalculators Factory invoked once
|
|
72
|
+
* per (key, thread) to build fresh calculator instances. A factory is
|
|
73
|
+
* required because calculator instances are stateful and bound to a
|
|
74
|
+
* propagator at construction time; they cannot be shared across keys.
|
|
75
|
+
* @param {number} params.satRecsCount Initial satellite-record allocation
|
|
76
|
+
* hint. Used only on first construction for this key in this thread.
|
|
77
|
+
* @param {number} params.datesCount Initial dates allocation hint. Same
|
|
78
|
+
* first-call-only semantics.
|
|
79
|
+
* @return {import("satellite.js").BulkPropagator<any, any>}
|
|
80
|
+
*/
|
|
81
|
+
const getOrCreateBulkPropagator = ({
|
|
82
|
+
runtime,
|
|
83
|
+
key,
|
|
84
|
+
makeCalculators,
|
|
85
|
+
satRecsCount,
|
|
86
|
+
datesCount,
|
|
87
|
+
}) => {
|
|
88
|
+
const cached = registry.get(key);
|
|
89
|
+
if (cached) {
|
|
90
|
+
return cached;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const propagator = new BulkPropagator({
|
|
94
|
+
runtime,
|
|
95
|
+
calculators: makeCalculators(),
|
|
96
|
+
satRecsCount: Math.max(1, satRecsCount),
|
|
97
|
+
datesCount: Math.max(1, datesCount),
|
|
98
|
+
});
|
|
99
|
+
registry.set(key, propagator);
|
|
100
|
+
return propagator;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Releases all WASM memory owned by this thread: every registry-held
|
|
105
|
+
* `BulkPropagator` is disposed and the runtime itself is torn down.
|
|
106
|
+
*
|
|
107
|
+
* Idempotent: safe to call when nothing was ever initialized. After this
|
|
108
|
+
* returns, the next `getBulkRuntime()` will lazily re-initialize from
|
|
109
|
+
* scratch.
|
|
110
|
+
*/
|
|
111
|
+
const disposeBulkRuntime = async () => {
|
|
112
|
+
for (const propagator of registry.values()) {
|
|
113
|
+
try {
|
|
114
|
+
propagator.dispose();
|
|
115
|
+
} catch (e) {
|
|
116
|
+
// Disposal must never throw out of teardown; we surface the
|
|
117
|
+
// failure to stderr but continue cleaning up the rest of the
|
|
118
|
+
// registry to minimize the leak surface.
|
|
119
|
+
console.error("disposeBulkRuntime: failed to dispose propagator", e);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
registry = new Map();
|
|
123
|
+
|
|
124
|
+
if (runtimePromise !== null) {
|
|
125
|
+
const pending = runtimePromise;
|
|
126
|
+
runtimePromise = null;
|
|
127
|
+
try {
|
|
128
|
+
const runtime = await pending;
|
|
129
|
+
runtime.dispose();
|
|
130
|
+
} catch (e) {
|
|
131
|
+
// Emscripten's `_exit_runtime` (with EXIT_RUNTIME=1) signals clean
|
|
132
|
+
// shutdown by throwing an `ExitStatus` object with `status === 0`.
|
|
133
|
+
// That is the documented success path, not a failure to log.
|
|
134
|
+
if (e?.name !== "ExitStatus" || e?.status !== 0) {
|
|
135
|
+
console.error("disposeBulkRuntime: failed to dispose runtime", e);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
getBulkRuntime,
|
|
143
|
+
initBulkRuntime,
|
|
144
|
+
isBulkRuntimeInitialized,
|
|
145
|
+
getOrCreateBulkPropagator,
|
|
146
|
+
disposeBulkRuntime,
|
|
147
|
+
};
|