@smoothbricks/lmao 0.2.2 → 0.2.3
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/dist/allocator.wasm +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/JsBufferStrategy.d.ts +4 -3
- package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
- package/dist/lib/JsBufferStrategy.js +18 -11
- package/dist/lib/arrow/lease.d.ts +10 -0
- package/dist/lib/arrow/lease.d.ts.map +1 -0
- package/dist/lib/arrow/lease.js +33 -0
- package/dist/lib/arrow/utils.d.ts +3 -4
- package/dist/lib/arrow/utils.d.ts.map +1 -1
- package/dist/lib/arrow/utils.js +12 -13
- package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
- package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
- package/dist/lib/arrow/vocabularyDictionary.js +95 -0
- package/dist/lib/bufferStrategy.d.ts +3 -2
- package/dist/lib/bufferStrategy.d.ts.map +1 -1
- package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
- package/dist/lib/cloudflare/traceRows.js +3 -2
- package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/evaluatorGenerator.js +12 -11
- package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
- package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
- package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
- package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
- package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
- package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
- package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
- package/dist/lib/convertToArrow.d.ts +7 -2
- package/dist/lib/convertToArrow.d.ts.map +1 -1
- package/dist/lib/convertToArrow.js +499 -285
- package/dist/lib/defineOpContext.js +1 -1
- package/dist/lib/enumMetadata.d.ts +19 -0
- package/dist/lib/enumMetadata.d.ts.map +1 -0
- package/dist/lib/enumMetadata.js +86 -0
- package/dist/lib/flushScheduler.d.ts.map +1 -1
- package/dist/lib/flushScheduler.js +13 -4
- package/dist/lib/library.d.ts +16 -98
- package/dist/lib/library.d.ts.map +1 -1
- package/dist/lib/library.js +32 -525
- package/dist/lib/logBinding.d.ts +21 -27
- package/dist/lib/logBinding.d.ts.map +1 -1
- package/dist/lib/op.d.ts +30 -30
- package/dist/lib/op.d.ts.map +1 -1
- package/dist/lib/op.js +15 -22
- package/dist/lib/opContext/createOpGroup.d.ts +1 -1
- package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
- package/dist/lib/opContext/createOpGroup.js +22 -29
- package/dist/lib/opContext/defineOp.d.ts +4 -4
- package/dist/lib/opContext/defineOp.d.ts.map +1 -1
- package/dist/lib/opContext/defineOp.js +53 -10
- package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
- package/dist/lib/opContext/opTypes.d.ts +1 -1
- package/dist/lib/opContext/opTypes.d.ts.map +1 -1
- package/dist/lib/opContext/spanContextTypes.d.ts +29 -14
- package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
- package/dist/lib/opContext/types.d.ts +4 -4
- package/dist/lib/opContext/types.d.ts.map +1 -1
- package/dist/lib/physicalLayoutPlan.d.ts +89 -0
- package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
- package/dist/lib/physicalLayoutPlan.js +442 -0
- package/dist/lib/resolveMessage.d.ts +9 -0
- package/dist/lib/resolveMessage.d.ts.map +1 -0
- package/dist/lib/resolveMessage.js +63 -0
- package/dist/lib/result.d.ts +5 -7
- package/dist/lib/result.d.ts.map +1 -1
- package/dist/lib/result.js +19 -26
- package/dist/lib/runtimeHint.d.ts +35 -0
- package/dist/lib/runtimeHint.d.ts.map +1 -0
- package/dist/lib/runtimeHint.js +79 -0
- package/dist/lib/schema/types.d.ts +1 -1
- package/dist/lib/schema/types.d.ts.map +1 -1
- package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
- package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
- package/dist/lib/span-buffer/aot/v1.js +24 -0
- package/dist/lib/spanBuffer.d.ts +33 -4
- package/dist/lib/spanBuffer.d.ts.map +1 -1
- package/dist/lib/spanBuffer.js +583 -91
- package/dist/lib/spanBufferStats.d.ts +1 -1
- package/dist/lib/spanBufferStats.d.ts.map +1 -1
- package/dist/lib/spanContext.d.ts +27 -51
- package/dist/lib/spanContext.d.ts.map +1 -1
- package/dist/lib/spanContext.js +822 -344
- package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
- package/dist/lib/sqlite/sqlite-common.js +20 -21
- package/dist/lib/testing/bun-harness.d.ts +8 -3
- package/dist/lib/testing/bun-harness.d.ts.map +1 -1
- package/dist/lib/testing/bun-harness.js +30 -18
- package/dist/lib/testing/extractFacts.d.ts +1 -1
- package/dist/lib/testing/extractFacts.d.ts.map +1 -1
- package/dist/lib/testing/extractFacts.js +55 -63
- package/dist/lib/testing/facts.d.ts +1 -1
- package/dist/lib/testing/facts.d.ts.map +1 -1
- package/dist/lib/testing/queryable-span.d.ts +1 -1
- package/dist/lib/testing/queryable-span.d.ts.map +1 -1
- package/dist/lib/testing/queryable-span.js +26 -28
- package/dist/lib/testing/span-query.d.ts.map +1 -1
- package/dist/lib/testing/span-query.js +19 -22
- package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
- package/dist/lib/testing/stdio-replay.js +19 -8
- package/dist/lib/threadId.d.ts.map +1 -1
- package/dist/lib/threadId.js +6 -3
- package/dist/lib/traceRoot.d.ts +30 -8
- package/dist/lib/traceRoot.d.ts.map +1 -1
- package/dist/lib/traceRoot.es.d.ts +17 -15
- package/dist/lib/traceRoot.es.d.ts.map +1 -1
- package/dist/lib/traceRoot.es.js +68 -34
- package/dist/lib/traceRoot.js +11 -0
- package/dist/lib/traceRoot.node.d.ts +17 -19
- package/dist/lib/traceRoot.node.d.ts.map +1 -1
- package/dist/lib/traceRoot.node.js +66 -38
- package/dist/lib/traceTopology.d.ts +42 -0
- package/dist/lib/traceTopology.d.ts.map +1 -0
- package/dist/lib/traceTopology.js +260 -0
- package/dist/lib/tracer.d.ts +9 -5
- package/dist/lib/tracer.d.ts.map +1 -1
- package/dist/lib/tracer.js +65 -71
- package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
- package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
- package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
- package/dist/lib/tracers/StdioTracer.js +15 -13
- package/dist/lib/tracers/TestTracer.d.ts +4 -6
- package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
- package/dist/lib/tracers/TestTracer.js +6 -8
- package/dist/lib/types.d.ts +49 -32
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/vocabularyRegistry.d.ts +25 -0
- package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
- package/dist/lib/vocabularyRegistry.js +372 -0
- package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
- package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
- package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
- package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
- package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
- package/dist/lib/wasm/wasmAllocator.js +66 -44
- package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
- package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
- package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
- package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
- package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
- package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
- package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
- package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
- package/dist/lib/wasm/wasmTraceRoot.js +110 -71
- package/dist/vocabulary/register/v1.d.ts +2 -0
- package/dist/vocabulary/register/v1.d.ts.map +1 -0
- package/dist/vocabulary/register/v1.js +1 -0
- package/dist/wasm.d.ts +5 -0
- package/dist/wasm.d.ts.map +1 -0
- package/dist/wasm.js +4 -0
- package/package.json +54 -6
- package/src/index.ts +1 -0
- package/src/lib/JsBufferStrategy.ts +27 -9
- package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
- package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
- package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
- package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
- package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
- package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
- package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
- package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
- package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
- package/src/lib/__tests__/capability-span-context.test.ts +505 -0
- package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
- package/src/lib/__tests__/eager-columns.test.ts +345 -0
- package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
- package/src/lib/__tests__/enum-metadata.test.ts +177 -0
- package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
- package/src/lib/__tests__/flushScheduler.test.ts +5 -1
- package/src/lib/__tests__/identity-view.property.test.ts +179 -0
- package/src/lib/__tests__/library.test.ts +19 -235
- package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
- package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
- package/src/lib/__tests__/op-metadata.test.ts +1 -1
- package/src/lib/__tests__/op-type-safety.test.ts +5 -16
- package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
- package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
- package/src/lib/__tests__/root-context-construction.test.ts +414 -0
- package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
- package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
- package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
- package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
- package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
- package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
- package/src/lib/__tests__/test-helpers.ts +67 -12
- package/src/lib/__tests__/threadId.test.ts +62 -0
- package/src/lib/__tests__/timestamp.test.ts +221 -93
- package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
- package/src/lib/__tests__/type-narrowing.test.ts +63 -0
- package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
- package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
- package/src/lib/arrow/lease.ts +43 -0
- package/src/lib/arrow/utils.ts +10 -14
- package/src/lib/arrow/vocabularyDictionary.ts +123 -0
- package/src/lib/bufferStrategy.ts +9 -1
- package/src/lib/cloudflare/traceRows.ts +3 -2
- package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
- package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
- package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
- package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
- package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
- package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
- package/src/lib/codegen/evaluatorGenerator.ts +18 -13
- package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
- package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
- package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
- package/src/lib/convertToArrow.ts +598 -311
- package/src/lib/defineOpContext.ts +1 -1
- package/src/lib/enumMetadata.ts +121 -0
- package/src/lib/flushScheduler.ts +11 -5
- package/src/lib/library.ts +37 -595
- package/src/lib/logBinding.ts +21 -27
- package/src/lib/op.ts +75 -18
- package/src/lib/opContext/__tests__/retry.test.ts +27 -21
- package/src/lib/opContext/createOpGroup.ts +33 -31
- package/src/lib/opContext/defineOp.ts +88 -11
- package/src/lib/opContext/opGroupTypes.ts +2 -2
- package/src/lib/opContext/opTypes.ts +1 -1
- package/src/lib/opContext/spanContextTypes.ts +98 -17
- package/src/lib/opContext/types.ts +7 -3
- package/src/lib/physicalLayoutPlan.ts +598 -0
- package/src/lib/resolveMessage.ts +67 -0
- package/src/lib/result.ts +20 -33
- package/src/lib/runtimeHint.ts +98 -0
- package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
- package/src/lib/schema/builder.ts +1 -1
- package/src/lib/schema/types.ts +1 -1
- package/src/lib/span-buffer/aot/v1.ts +26 -0
- package/src/lib/spanBuffer.ts +658 -92
- package/src/lib/spanBufferStats.ts +1 -1
- package/src/lib/spanContext.ts +1350 -861
- package/src/lib/sqlite/sqlite-common.ts +20 -31
- package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
- package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
- package/src/lib/testing/bun-harness.ts +94 -43
- package/src/lib/testing/extractFacts.ts +64 -78
- package/src/lib/testing/facts.ts +1 -1
- package/src/lib/testing/queryable-span.ts +23 -30
- package/src/lib/testing/span-query.ts +16 -20
- package/src/lib/testing/stdio-replay.ts +25 -8
- package/src/lib/testing/vitest-harness.ts +1 -1
- package/src/lib/threadId.ts +6 -3
- package/src/lib/traceRoot.es.ts +77 -42
- package/src/lib/traceRoot.node.ts +75 -46
- package/src/lib/traceRoot.ts +41 -14
- package/src/lib/traceTopology.ts +279 -0
- package/src/lib/tracer.ts +109 -98
- package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
- package/src/lib/tracers/StdioTracer.ts +15 -13
- package/src/lib/tracers/TestTracer.ts +6 -8
- package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
- package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
- package/src/lib/types.ts +64 -33
- package/src/lib/vocabularyRegistry.ts +439 -0
- package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
- package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
- package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
- package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
- package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
- package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
- package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
- package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
- package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
- package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
- package/src/lib/wasm/wasmAllocator.ts +131 -96
- package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
- package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
- package/src/lib/wasm/wasmTraceRoot.ts +140 -78
- package/src/vocabulary/register/v1.ts +1 -0
- package/src/wasm.ts +19 -0
- package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
- package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
- package/src/lib/wasm/allocator.zig +0 -948
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
export const REGISTER_VOCABULARY = Symbol.for('@smoothbricks/lmao/vocabulary/register/v1');
|
|
2
|
+
|
|
3
|
+
const VOCABULARY_STATE = Symbol.for('@smoothbricks/lmao/vocabulary/state/v1');
|
|
4
|
+
const SCHEMA_VERSION = 1;
|
|
5
|
+
const ID_ALGORITHM = 'sha256-24-v1';
|
|
6
|
+
const MAX_VOCABULARY_ID = 0x00ff_ffff;
|
|
7
|
+
const CONTENT_HASH_PATTERN = /^[0-9a-f]{64}$/;
|
|
8
|
+
const SHA256_INITIAL = new Uint32Array([
|
|
9
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
10
|
+
]);
|
|
11
|
+
const SHA256_ROUND = new Uint32Array([
|
|
12
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
|
|
13
|
+
0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
|
14
|
+
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8,
|
|
15
|
+
0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
16
|
+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
|
17
|
+
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
|
18
|
+
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
|
19
|
+
0xc67178f2,
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
export interface VocabularyFragment {
|
|
23
|
+
readonly schemaVersion: 1;
|
|
24
|
+
readonly idAlgorithm: 'sha256-24-v1';
|
|
25
|
+
readonly contentHash: string;
|
|
26
|
+
readonly ids: Uint32Array;
|
|
27
|
+
readonly kindTags: Uint8Array;
|
|
28
|
+
readonly utf8: Uint8Array;
|
|
29
|
+
readonly offsets: Int32Array;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type VocabularyBinding = Uint32Array;
|
|
33
|
+
|
|
34
|
+
export interface VocabularyGeneration {
|
|
35
|
+
readonly generation: number;
|
|
36
|
+
readonly ids: Uint32Array;
|
|
37
|
+
readonly kindTags: Uint8Array;
|
|
38
|
+
readonly records: Uint8Array;
|
|
39
|
+
readonly offsets: Int32Array;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type RegisteredFragment = {
|
|
43
|
+
readonly ids: Uint32Array;
|
|
44
|
+
readonly kindTags: Uint8Array;
|
|
45
|
+
readonly utf8: Uint8Array;
|
|
46
|
+
readonly offsets: Int32Array;
|
|
47
|
+
readonly binding: VocabularyBinding;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type RegisteredEntry = {
|
|
51
|
+
readonly kindTag: number;
|
|
52
|
+
readonly record: Uint8Array;
|
|
53
|
+
readonly denseIndex: number;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type VocabularyState = {
|
|
57
|
+
readonly entriesById: Map<number, RegisteredEntry>;
|
|
58
|
+
readonly fragmentsByHash: Map<string, RegisteredFragment>;
|
|
59
|
+
readonly generations: VocabularyGeneration[];
|
|
60
|
+
current: VocabularyGeneration;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export class VocabularyRegistrationError extends Error {
|
|
64
|
+
override readonly name = 'VocabularyRegistrationError';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const decoder = new TextDecoder('utf-8', { fatal: true });
|
|
68
|
+
const algorithmBytes = new TextEncoder().encode(ID_ALGORITHM);
|
|
69
|
+
|
|
70
|
+
function fail(code: string, detail: string): never {
|
|
71
|
+
throw new VocabularyRegistrationError(`${code}: ${detail}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function rotateRight(value: number, count: number): number {
|
|
75
|
+
return (value >>> count) | (value << (32 - count));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function sha256(input: Uint8Array): Uint8Array {
|
|
79
|
+
const bitLength = input.length * 8;
|
|
80
|
+
const paddedLength = (input.length + 9 + 63) & ~63;
|
|
81
|
+
const padded = new Uint8Array(paddedLength);
|
|
82
|
+
padded.set(input);
|
|
83
|
+
padded[input.length] = 0x80;
|
|
84
|
+
const view = new DataView(padded.buffer);
|
|
85
|
+
view.setUint32(paddedLength - 8, Math.floor(bitLength / 0x1_0000_0000), false);
|
|
86
|
+
view.setUint32(paddedLength - 4, bitLength >>> 0, false);
|
|
87
|
+
|
|
88
|
+
const hash = SHA256_INITIAL.slice();
|
|
89
|
+
const words = new Uint32Array(64);
|
|
90
|
+
for (let block = 0; block < paddedLength; block += 64) {
|
|
91
|
+
for (let index = 0; index < 16; index++) words[index] = view.getUint32(block + index * 4, false);
|
|
92
|
+
for (let index = 16; index < 64; index++) {
|
|
93
|
+
const x = words[index - 15];
|
|
94
|
+
const y = words[index - 2];
|
|
95
|
+
const sigma0 = rotateRight(x, 7) ^ rotateRight(x, 18) ^ (x >>> 3);
|
|
96
|
+
const sigma1 = rotateRight(y, 17) ^ rotateRight(y, 19) ^ (y >>> 10);
|
|
97
|
+
words[index] = (words[index - 16] + sigma0 + words[index - 7] + sigma1) >>> 0;
|
|
98
|
+
}
|
|
99
|
+
let a = hash[0];
|
|
100
|
+
let b = hash[1];
|
|
101
|
+
let c = hash[2];
|
|
102
|
+
let d = hash[3];
|
|
103
|
+
let e = hash[4];
|
|
104
|
+
let f = hash[5];
|
|
105
|
+
let g = hash[6];
|
|
106
|
+
let h = hash[7];
|
|
107
|
+
for (let index = 0; index < 64; index++) {
|
|
108
|
+
const sum1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
|
|
109
|
+
const choose = (e & f) ^ (~e & g);
|
|
110
|
+
const temp1 = (h + sum1 + choose + SHA256_ROUND[index] + words[index]) >>> 0;
|
|
111
|
+
const sum0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
|
|
112
|
+
const majority = (a & b) ^ (a & c) ^ (b & c);
|
|
113
|
+
const temp2 = (sum0 + majority) >>> 0;
|
|
114
|
+
h = g;
|
|
115
|
+
g = f;
|
|
116
|
+
f = e;
|
|
117
|
+
e = (d + temp1) >>> 0;
|
|
118
|
+
d = c;
|
|
119
|
+
c = b;
|
|
120
|
+
b = a;
|
|
121
|
+
a = (temp1 + temp2) >>> 0;
|
|
122
|
+
}
|
|
123
|
+
hash[0] = (hash[0] + a) >>> 0;
|
|
124
|
+
hash[1] = (hash[1] + b) >>> 0;
|
|
125
|
+
hash[2] = (hash[2] + c) >>> 0;
|
|
126
|
+
hash[3] = (hash[3] + d) >>> 0;
|
|
127
|
+
hash[4] = (hash[4] + e) >>> 0;
|
|
128
|
+
hash[5] = (hash[5] + f) >>> 0;
|
|
129
|
+
hash[6] = (hash[6] + g) >>> 0;
|
|
130
|
+
hash[7] = (hash[7] + h) >>> 0;
|
|
131
|
+
}
|
|
132
|
+
const result = new Uint8Array(32);
|
|
133
|
+
const resultView = new DataView(result.buffer);
|
|
134
|
+
for (let index = 0; index < hash.length; index++) resultView.setUint32(index * 4, hash[index], false);
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function hex(bytes: Uint8Array): string {
|
|
139
|
+
let result = '';
|
|
140
|
+
for (const byte of bytes) result += byte.toString(16).padStart(2, '0');
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function equalBytes(
|
|
145
|
+
left: Uint8Array | Uint32Array | Int32Array,
|
|
146
|
+
right: Uint8Array | Uint32Array | Int32Array,
|
|
147
|
+
): boolean {
|
|
148
|
+
if (left.constructor !== right.constructor || left.length !== right.length) return false;
|
|
149
|
+
for (let index = 0; index < left.length; index++) if (left[index] !== right[index]) return false;
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function samePayload(registered: RegisteredFragment, fragment: VocabularyFragment): boolean {
|
|
154
|
+
return (
|
|
155
|
+
equalBytes(registered.ids, fragment.ids) &&
|
|
156
|
+
equalBytes(registered.kindTags, fragment.kindTags) &&
|
|
157
|
+
equalBytes(registered.utf8, fragment.utf8) &&
|
|
158
|
+
equalBytes(registered.offsets, fragment.offsets)
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function recordAt(fragment: VocabularyFragment, ordinal: number): Uint8Array {
|
|
163
|
+
return fragment.utf8.subarray(fragment.offsets[ordinal], fragment.offsets[ordinal + 1]);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function validateRecord(record: Uint8Array, ordinal: number): void {
|
|
167
|
+
const view = new DataView(record.buffer, record.byteOffset, record.byteLength);
|
|
168
|
+
if (record.length < 6) fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} is truncated`);
|
|
169
|
+
let offset = 0;
|
|
170
|
+
const textLength = view.getUint32(offset, true);
|
|
171
|
+
offset += 4;
|
|
172
|
+
if (textLength > record.length - offset - 2)
|
|
173
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} text is truncated`);
|
|
174
|
+
try {
|
|
175
|
+
decoder.decode(record.subarray(offset, offset + textLength));
|
|
176
|
+
} catch {
|
|
177
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} text is not valid UTF-8`);
|
|
178
|
+
}
|
|
179
|
+
offset += textLength;
|
|
180
|
+
const fieldCount = view.getUint16(offset, true);
|
|
181
|
+
offset += 2;
|
|
182
|
+
for (let field = 0; field < fieldCount; field++) {
|
|
183
|
+
if (offset + 2 > record.length)
|
|
184
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} field ${field} name length is truncated`);
|
|
185
|
+
const nameLength = view.getUint16(offset, true);
|
|
186
|
+
offset += 2;
|
|
187
|
+
if (offset + nameLength + 2 > record.length)
|
|
188
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} field ${field} name is truncated`);
|
|
189
|
+
try {
|
|
190
|
+
decoder.decode(record.subarray(offset, offset + nameLength));
|
|
191
|
+
} catch {
|
|
192
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} field ${field} name is not valid UTF-8`);
|
|
193
|
+
}
|
|
194
|
+
offset += nameLength;
|
|
195
|
+
const columnLength = view.getUint16(offset, true);
|
|
196
|
+
offset += 2;
|
|
197
|
+
if (offset + columnLength > record.length)
|
|
198
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} field ${field} column is truncated`);
|
|
199
|
+
try {
|
|
200
|
+
decoder.decode(record.subarray(offset, offset + columnLength));
|
|
201
|
+
} catch {
|
|
202
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} field ${field} column is not valid UTF-8`);
|
|
203
|
+
}
|
|
204
|
+
offset += columnLength;
|
|
205
|
+
}
|
|
206
|
+
if (offset !== record.length) fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `record ${ordinal} has trailing bytes`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function contentHash(fragment: VocabularyFragment): string {
|
|
210
|
+
const size =
|
|
211
|
+
1 +
|
|
212
|
+
2 +
|
|
213
|
+
algorithmBytes.length +
|
|
214
|
+
4 +
|
|
215
|
+
fragment.ids.length * 4 +
|
|
216
|
+
4 +
|
|
217
|
+
fragment.kindTags.length +
|
|
218
|
+
4 +
|
|
219
|
+
fragment.utf8.length +
|
|
220
|
+
4 +
|
|
221
|
+
fragment.offsets.length * 4;
|
|
222
|
+
const bytes = new Uint8Array(size);
|
|
223
|
+
const view = new DataView(bytes.buffer);
|
|
224
|
+
let offset = 0;
|
|
225
|
+
bytes[offset++] = fragment.schemaVersion;
|
|
226
|
+
view.setUint16(offset, algorithmBytes.length, true);
|
|
227
|
+
offset += 2;
|
|
228
|
+
bytes.set(algorithmBytes, offset);
|
|
229
|
+
offset += algorithmBytes.length;
|
|
230
|
+
view.setUint32(offset, fragment.ids.length, true);
|
|
231
|
+
offset += 4;
|
|
232
|
+
for (const id of fragment.ids) {
|
|
233
|
+
view.setUint32(offset, id, true);
|
|
234
|
+
offset += 4;
|
|
235
|
+
}
|
|
236
|
+
view.setUint32(offset, fragment.kindTags.length, true);
|
|
237
|
+
offset += 4;
|
|
238
|
+
bytes.set(fragment.kindTags, offset);
|
|
239
|
+
offset += fragment.kindTags.length;
|
|
240
|
+
view.setUint32(offset, fragment.utf8.length, true);
|
|
241
|
+
offset += 4;
|
|
242
|
+
bytes.set(fragment.utf8, offset);
|
|
243
|
+
offset += fragment.utf8.length;
|
|
244
|
+
view.setUint32(offset, fragment.offsets.length, true);
|
|
245
|
+
offset += 4;
|
|
246
|
+
for (const boundary of fragment.offsets) {
|
|
247
|
+
view.setInt32(offset, boundary, true);
|
|
248
|
+
offset += 4;
|
|
249
|
+
}
|
|
250
|
+
return hex(sha256(bytes));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function createState(): VocabularyState {
|
|
254
|
+
const initial: VocabularyGeneration = Object.freeze({
|
|
255
|
+
generation: 0,
|
|
256
|
+
ids: new Uint32Array(0),
|
|
257
|
+
kindTags: new Uint8Array(0),
|
|
258
|
+
records: new Uint8Array(0),
|
|
259
|
+
offsets: new Int32Array([0]),
|
|
260
|
+
});
|
|
261
|
+
return { entriesById: new Map(), fragmentsByHash: new Map(), generations: [initial], current: initial };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function globalState(): VocabularyState {
|
|
265
|
+
const globals = globalThis as typeof globalThis & { [VOCABULARY_STATE]?: VocabularyState };
|
|
266
|
+
let state = globals[VOCABULARY_STATE];
|
|
267
|
+
if (state === undefined) {
|
|
268
|
+
state = createState();
|
|
269
|
+
Object.defineProperty(globals, VOCABULARY_STATE, {
|
|
270
|
+
value: state,
|
|
271
|
+
configurable: false,
|
|
272
|
+
enumerable: false,
|
|
273
|
+
writable: false,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
return state;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function validateFragmentStructure(fragment: VocabularyFragment): void {
|
|
280
|
+
if (fragment.schemaVersion !== SCHEMA_VERSION || fragment.idAlgorithm !== ID_ALGORITHM)
|
|
281
|
+
fail('LMAO_VOCABULARY_ABI_UNAVAILABLE', 'unsupported schema version or ID algorithm');
|
|
282
|
+
if (!CONTENT_HASH_PATTERN.test(fragment.contentHash))
|
|
283
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `invalid contentHash ${JSON.stringify(fragment.contentHash)}`);
|
|
284
|
+
if (
|
|
285
|
+
!(fragment.ids instanceof Uint32Array) ||
|
|
286
|
+
!(fragment.kindTags instanceof Uint8Array) ||
|
|
287
|
+
!(fragment.utf8 instanceof Uint8Array) ||
|
|
288
|
+
!(fragment.offsets instanceof Int32Array)
|
|
289
|
+
)
|
|
290
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', 'fragment arrays use incorrect types');
|
|
291
|
+
if (fragment.kindTags.length !== fragment.ids.length || fragment.offsets.length !== fragment.ids.length + 1)
|
|
292
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', 'parallel lengths differ');
|
|
293
|
+
if (fragment.offsets[0] !== 0 || fragment.offsets[fragment.offsets.length - 1] !== fragment.utf8.length)
|
|
294
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', 'offsets do not cover bytes');
|
|
295
|
+
const localOrdinals = new Map<number, number>();
|
|
296
|
+
for (let ordinal = 0; ordinal < fragment.ids.length; ordinal++) {
|
|
297
|
+
const id = fragment.ids[ordinal];
|
|
298
|
+
const kindTag = fragment.kindTags[ordinal];
|
|
299
|
+
if (id === 0 || id > MAX_VOCABULARY_ID) fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `stable ID ${id}`);
|
|
300
|
+
if (kindTag !== 1 && kindTag !== 2) fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `kind tag ${kindTag}`);
|
|
301
|
+
if (fragment.offsets[ordinal] > fragment.offsets[ordinal + 1])
|
|
302
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', 'offsets are not monotonic');
|
|
303
|
+
const record = recordAt(fragment, ordinal);
|
|
304
|
+
validateRecord(record, ordinal);
|
|
305
|
+
const idInput = new Uint8Array(record.length + 1);
|
|
306
|
+
idInput[0] = kindTag;
|
|
307
|
+
idInput.set(record, 1);
|
|
308
|
+
const digest = sha256(idInput);
|
|
309
|
+
const derivedId = (digest[0] << 16) | (digest[1] << 8) | digest[2];
|
|
310
|
+
if (id !== derivedId || id === 0)
|
|
311
|
+
fail('LMAO_VOCABULARY_FRAGMENT_INVALID', `stable ID ${id} does not match record ${ordinal}`);
|
|
312
|
+
const previousOrdinal = localOrdinals.get(id);
|
|
313
|
+
if (
|
|
314
|
+
previousOrdinal !== undefined &&
|
|
315
|
+
(fragment.kindTags[previousOrdinal] !== kindTag || !equalBytes(recordAt(fragment, previousOrdinal), record))
|
|
316
|
+
) {
|
|
317
|
+
fail('LMAO_VOCABULARY_ID_COLLISION', `stable ID ${id} within fragment`);
|
|
318
|
+
}
|
|
319
|
+
localOrdinals.set(id, ordinal);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function appendGeneration(
|
|
324
|
+
state: VocabularyState,
|
|
325
|
+
ids: readonly number[],
|
|
326
|
+
kindTags: readonly number[],
|
|
327
|
+
records: readonly Uint8Array[],
|
|
328
|
+
): void {
|
|
329
|
+
if (ids.length === 0) return;
|
|
330
|
+
const previous = state.current;
|
|
331
|
+
let byteLength = previous.records.length;
|
|
332
|
+
for (const record of records) byteLength += record.length;
|
|
333
|
+
const generationIds = new Uint32Array(previous.ids.length + ids.length);
|
|
334
|
+
generationIds.set(previous.ids);
|
|
335
|
+
generationIds.set(ids, previous.ids.length);
|
|
336
|
+
const generationKinds = new Uint8Array(previous.kindTags.length + kindTags.length);
|
|
337
|
+
generationKinds.set(previous.kindTags);
|
|
338
|
+
generationKinds.set(kindTags, previous.kindTags.length);
|
|
339
|
+
const generationRecords = new Uint8Array(byteLength);
|
|
340
|
+
generationRecords.set(previous.records);
|
|
341
|
+
const generationOffsets = new Int32Array(generationIds.length + 1);
|
|
342
|
+
generationOffsets.set(previous.offsets);
|
|
343
|
+
let byteOffset = previous.records.length;
|
|
344
|
+
for (let index = 0; index < records.length; index++) {
|
|
345
|
+
generationRecords.set(records[index], byteOffset);
|
|
346
|
+
byteOffset += records[index].length;
|
|
347
|
+
generationOffsets[previous.ids.length + index + 1] = byteOffset;
|
|
348
|
+
}
|
|
349
|
+
const generation: VocabularyGeneration = Object.freeze({
|
|
350
|
+
generation: previous.generation + 1,
|
|
351
|
+
ids: generationIds,
|
|
352
|
+
kindTags: generationKinds,
|
|
353
|
+
records: generationRecords,
|
|
354
|
+
offsets: generationOffsets,
|
|
355
|
+
});
|
|
356
|
+
state.generations.push(generation);
|
|
357
|
+
state.current = generation;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function registerVocabulary(fragment: VocabularyFragment): VocabularyBinding {
|
|
361
|
+
validateFragmentStructure(fragment);
|
|
362
|
+
const state = globalState();
|
|
363
|
+
const sameHash = state.fragmentsByHash.get(fragment.contentHash);
|
|
364
|
+
if (sameHash !== undefined) {
|
|
365
|
+
if (!samePayload(sameHash, fragment)) fail('LMAO_VOCABULARY_CONTENT_HASH_COLLISION', fragment.contentHash);
|
|
366
|
+
return sameHash.binding;
|
|
367
|
+
}
|
|
368
|
+
if (contentHash(fragment) !== fragment.contentHash) {
|
|
369
|
+
fail('LMAO_VOCABULARY_CONTENT_HASH_MISMATCH', fragment.contentHash);
|
|
370
|
+
}
|
|
371
|
+
for (let ordinal = 0; ordinal < fragment.ids.length; ordinal++) {
|
|
372
|
+
const existing = state.entriesById.get(fragment.ids[ordinal]);
|
|
373
|
+
if (
|
|
374
|
+
existing !== undefined &&
|
|
375
|
+
(existing.kindTag !== fragment.kindTags[ordinal] || !equalBytes(existing.record, recordAt(fragment, ordinal)))
|
|
376
|
+
)
|
|
377
|
+
fail('LMAO_VOCABULARY_ID_COLLISION', `stable ID ${fragment.ids[ordinal]}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const binding = new Uint32Array(fragment.ids.length);
|
|
381
|
+
const appendedIds: number[] = [];
|
|
382
|
+
const appendedKinds: number[] = [];
|
|
383
|
+
const appendedRecords: Uint8Array[] = [];
|
|
384
|
+
for (let ordinal = 0; ordinal < fragment.ids.length; ordinal++) {
|
|
385
|
+
const id = fragment.ids[ordinal];
|
|
386
|
+
let existing = state.entriesById.get(id);
|
|
387
|
+
if (existing === undefined) {
|
|
388
|
+
const record = recordAt(fragment, ordinal).slice();
|
|
389
|
+
existing = {
|
|
390
|
+
kindTag: fragment.kindTags[ordinal],
|
|
391
|
+
record,
|
|
392
|
+
denseIndex: state.current.ids.length + appendedIds.length,
|
|
393
|
+
};
|
|
394
|
+
state.entriesById.set(id, existing);
|
|
395
|
+
appendedIds.push(id);
|
|
396
|
+
appendedKinds.push(existing.kindTag);
|
|
397
|
+
appendedRecords.push(record);
|
|
398
|
+
}
|
|
399
|
+
binding[ordinal] = existing.denseIndex;
|
|
400
|
+
}
|
|
401
|
+
appendGeneration(state, appendedIds, appendedKinds, appendedRecords);
|
|
402
|
+
state.fragmentsByHash.set(fragment.contentHash, {
|
|
403
|
+
ids: fragment.ids.slice(),
|
|
404
|
+
kindTags: fragment.kindTags.slice(),
|
|
405
|
+
utf8: fragment.utf8.slice(),
|
|
406
|
+
offsets: fragment.offsets.slice(),
|
|
407
|
+
binding,
|
|
408
|
+
});
|
|
409
|
+
return binding;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export type RegisterVocabulary = (fragment: VocabularyFragment) => VocabularyBinding;
|
|
413
|
+
|
|
414
|
+
function isRegisterVocabulary(value: unknown): value is RegisterVocabulary {
|
|
415
|
+
return typeof value === 'function';
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function installVocabularyRegistration(): RegisterVocabulary {
|
|
419
|
+
const globals = globalThis as typeof globalThis & { [REGISTER_VOCABULARY]?: unknown };
|
|
420
|
+
const installed = globals[REGISTER_VOCABULARY];
|
|
421
|
+
if (installed !== undefined) {
|
|
422
|
+
if (!isRegisterVocabulary(installed))
|
|
423
|
+
fail('LMAO_VOCABULARY_ABI_UNAVAILABLE', 'global symbol contains a non-function');
|
|
424
|
+
return installed;
|
|
425
|
+
}
|
|
426
|
+
Object.defineProperty(globals, REGISTER_VOCABULARY, {
|
|
427
|
+
value: registerVocabulary,
|
|
428
|
+
configurable: false,
|
|
429
|
+
enumerable: false,
|
|
430
|
+
writable: false,
|
|
431
|
+
});
|
|
432
|
+
return registerVocabulary;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export const registerVocabularyFragment = installVocabularyRegistration();
|
|
436
|
+
|
|
437
|
+
export function getVocabularyGeneration(): VocabularyGeneration {
|
|
438
|
+
return globalState().current;
|
|
439
|
+
}
|
|
@@ -18,8 +18,9 @@ import type { BufferStrategy } from '../bufferStrategy.js';
|
|
|
18
18
|
import { convertSpanTreeToArrowTable } from '../convertToArrow.js';
|
|
19
19
|
import type { OpMetadata } from '../opContext/opTypes.js';
|
|
20
20
|
import type { LogSchema } from '../schema/LogSchema.js';
|
|
21
|
-
import { EMPTY_SCOPE } from '../spanBuffer.js';
|
|
21
|
+
import { EMPTY_SCOPE, type SpanBufferConstructor } from '../spanBuffer.js';
|
|
22
22
|
import type { ITraceRoot } from '../traceRoot.js';
|
|
23
|
+
import { walkSpanTree } from '../traceTopology.js';
|
|
23
24
|
import type { AnySpanBuffer, SpanBuffer } from '../types.js';
|
|
24
25
|
import { createWasmAllocator, type WasmAllocator, type WasmAllocatorOptions } from './wasmAllocator.js';
|
|
25
26
|
import {
|
|
@@ -29,14 +30,13 @@ import {
|
|
|
29
30
|
isWasmSpanBufferInstance,
|
|
30
31
|
type WasmSpanBufferInstance,
|
|
31
32
|
} from './wasmSpanBuffer.js';
|
|
33
|
+
import { WasmTraceRoot } from './wasmTraceRoot.js';
|
|
32
34
|
|
|
33
35
|
// Spec link (88): realizes specs/lmao/01q_wasm_memory_architecture.md#smoo/lmao!n/wasm-mem (OpContext integration + trace completion).
|
|
34
36
|
//#region smoo/lmao!n/wasm-mem.strategy
|
|
35
37
|
|
|
36
|
-
function requireWasmSpanBuffer(buffer:
|
|
37
|
-
if (!isWasmSpanBufferInstance(buffer))
|
|
38
|
-
throw new Error('Expected WASM-backed span buffer');
|
|
39
|
-
}
|
|
38
|
+
function requireWasmSpanBuffer<T extends LogSchema>(buffer: unknown): WasmSpanBufferInstance<T> {
|
|
39
|
+
if (!isWasmSpanBufferInstance<T>(buffer)) throw new Error('Expected WASM-backed span buffer');
|
|
40
40
|
return buffer;
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -75,6 +75,7 @@ export class WasmBufferStrategy<T extends LogSchema = LogSchema> implements Buff
|
|
|
75
75
|
* Shared across all buffers created by this strategy.
|
|
76
76
|
*/
|
|
77
77
|
readonly allocator: WasmAllocator;
|
|
78
|
+
private readonly liveRoots = new Set<WasmSpanBufferInstance<T>>();
|
|
78
79
|
|
|
79
80
|
/**
|
|
80
81
|
* Private constructor - use static create() method.
|
|
@@ -98,28 +99,34 @@ export class WasmBufferStrategy<T extends LogSchema = LogSchema> implements Buff
|
|
|
98
99
|
return new WasmBufferStrategy<T>(allocator);
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
createSpanBuffer(
|
|
102
|
+
createSpanBuffer(
|
|
103
|
+
schema: T,
|
|
104
|
+
traceRoot: ITraceRoot<T>,
|
|
105
|
+
opMetadata: OpMetadata,
|
|
106
|
+
capacity?: number,
|
|
107
|
+
plannedClass?: SpanBufferConstructor<T>,
|
|
108
|
+
): SpanBuffer<T> {
|
|
102
109
|
const effectiveCapacity = capacity ?? this.allocator.capacity;
|
|
103
|
-
|
|
110
|
+
const messageLayoutFamily = plannedClass?.messageLayoutFamily ?? 'mixed';
|
|
111
|
+
const messagePhysicalLayout = plannedClass?.messagePhysicalLayout ?? 'current';
|
|
104
112
|
// Create WASM buffer
|
|
105
113
|
const wasmBuffer = createWasmSpanBuffer(
|
|
106
114
|
schema,
|
|
107
115
|
{
|
|
108
116
|
allocator: this.allocator,
|
|
109
117
|
capacity: effectiveCapacity,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
thread_id: 0n, // Will be read from WASM header
|
|
113
|
-
span_id: 0, // Will be assigned by WASM allocator
|
|
118
|
+
messageLayoutFamily,
|
|
119
|
+
messagePhysicalLayout,
|
|
114
120
|
},
|
|
115
121
|
traceRoot, // _traceRoot
|
|
116
122
|
EMPTY_SCOPE, // _scopeValues
|
|
117
123
|
opMetadata, // _opMetadata
|
|
118
124
|
opMetadata, // _callsiteMetadata (same as opMetadata for root)
|
|
119
125
|
);
|
|
126
|
+
traceRoot._topology.registerRoot(wasmBuffer);
|
|
127
|
+
this.liveRoots.add(wasmBuffer);
|
|
120
128
|
|
|
121
|
-
|
|
122
|
-
return wasmBuffer as unknown as SpanBuffer<T>;
|
|
129
|
+
return wasmBuffer;
|
|
123
130
|
}
|
|
124
131
|
|
|
125
132
|
createChildSpanBuffer(
|
|
@@ -128,34 +135,37 @@ export class WasmBufferStrategy<T extends LogSchema = LogSchema> implements Buff
|
|
|
128
135
|
opMetadata: OpMetadata,
|
|
129
136
|
capacity?: number,
|
|
130
137
|
schema?: T,
|
|
138
|
+
plannedClass?: SpanBufferConstructor<T>,
|
|
131
139
|
): SpanBuffer<T> {
|
|
132
|
-
const wasmParent = requireWasmSpanBuffer(parentBuffer);
|
|
140
|
+
const wasmParent = requireWasmSpanBuffer<T>(parentBuffer);
|
|
133
141
|
const effectiveCapacity = capacity ?? wasmParent._capacity;
|
|
134
142
|
|
|
135
143
|
// Use provided schema (for cross-library calls) or parent's schema
|
|
136
|
-
const childSchema = schema ??
|
|
144
|
+
const childSchema = schema ?? parentBuffer._logSchema;
|
|
145
|
+
const messageLayoutFamily = plannedClass?.messageLayoutFamily ?? wasmParent._messageLayoutFamily;
|
|
146
|
+
const messagePhysicalLayout = plannedClass?.messagePhysicalLayout ?? wasmParent._messagePhysicalLayout;
|
|
137
147
|
|
|
138
148
|
const child = createWasmChildSpanBuffer(
|
|
139
149
|
wasmParent,
|
|
140
150
|
{
|
|
141
151
|
allocator: this.allocator,
|
|
142
152
|
capacity: effectiveCapacity,
|
|
143
|
-
thread_id: 0n, // Will be read from WASM header
|
|
144
|
-
span_id: 0, // Will be assigned by WASM allocator
|
|
145
153
|
schema: childSchema, // Pass schema for correct buffer class
|
|
154
|
+
messageLayoutFamily,
|
|
155
|
+
messagePhysicalLayout,
|
|
146
156
|
},
|
|
147
157
|
parentBuffer._traceRoot, // _traceRoot (inherit from parent)
|
|
148
158
|
parentBuffer._scopeValues, // _scopeValues (inherit from parent)
|
|
149
159
|
opMetadata, // _opMetadata
|
|
150
160
|
callsiteMetadata, // _callsiteMetadata
|
|
151
161
|
);
|
|
162
|
+
parentBuffer._traceRoot._topology.registerChild(parentBuffer, child);
|
|
152
163
|
|
|
153
|
-
|
|
154
|
-
return child as unknown as SpanBuffer<T>;
|
|
164
|
+
return child;
|
|
155
165
|
}
|
|
156
166
|
|
|
157
167
|
createOverflowBuffer(buffer: SpanBuffer<T>): SpanBuffer<T> {
|
|
158
|
-
const wasmBuffer = requireWasmSpanBuffer(buffer);
|
|
168
|
+
const wasmBuffer = requireWasmSpanBuffer<T>(buffer);
|
|
159
169
|
const overflow = createWasmOverflowBuffer(
|
|
160
170
|
wasmBuffer,
|
|
161
171
|
buffer._traceRoot, // _traceRoot (same as original)
|
|
@@ -163,9 +173,9 @@ export class WasmBufferStrategy<T extends LogSchema = LogSchema> implements Buff
|
|
|
163
173
|
buffer._opMetadata, // _opMetadata (same as original)
|
|
164
174
|
buffer._callsiteMetadata ?? buffer._opMetadata, // _callsiteMetadata (same as original, fallback to opMetadata)
|
|
165
175
|
);
|
|
176
|
+
buffer._traceRoot._topology.adoptOverflow(buffer, overflow);
|
|
166
177
|
|
|
167
|
-
|
|
168
|
-
return overflow as unknown as SpanBuffer<T>;
|
|
178
|
+
return overflow;
|
|
169
179
|
}
|
|
170
180
|
|
|
171
181
|
toArrowTable(buffer: AnySpanBuffer): Table {
|
|
@@ -174,37 +184,35 @@ export class WasmBufferStrategy<T extends LogSchema = LogSchema> implements Buff
|
|
|
174
184
|
}
|
|
175
185
|
|
|
176
186
|
releaseBuffer(buffer: AnySpanBuffer): void {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// Free children first (depth-first)
|
|
186
|
-
if (buffer._children) {
|
|
187
|
-
for (const child of buffer._children) {
|
|
188
|
-
this.freeSpanTree(child);
|
|
187
|
+
const root = requireWasmSpanBuffer<T>(buffer);
|
|
188
|
+
const segments: WasmSpanBufferInstance<T>[] = [];
|
|
189
|
+
walkSpanTree(root, (segment) => segments.push(requireWasmSpanBuffer<T>(segment)));
|
|
190
|
+
const topology = root._traceRoot._topology;
|
|
191
|
+
topology.release(() => {
|
|
192
|
+
for (const segment of segments) segment.free();
|
|
193
|
+
if (root._descriptor.kind === 'root' && root._traceRoot instanceof WasmTraceRoot) {
|
|
194
|
+
root._traceRoot.free();
|
|
189
195
|
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (buffer._overflow) {
|
|
194
|
-
this.freeSpanTree(buffer._overflow);
|
|
195
|
-
}
|
|
196
|
+
});
|
|
197
|
+
this.liveRoots.delete(root);
|
|
198
|
+
}
|
|
196
199
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
private invalidateSpanTree(buffer: WasmSpanBufferInstance<T>): void {
|
|
201
|
+
walkSpanTree(buffer, (segment) => {
|
|
202
|
+
const wasmSegment = requireWasmSpanBuffer<T>(segment);
|
|
203
|
+
wasmSegment._columnPtrs.fill(-1);
|
|
204
|
+
wasmSegment._descriptor.state = 'freed';
|
|
205
|
+
});
|
|
201
206
|
}
|
|
202
207
|
|
|
203
|
-
/**
|
|
204
|
-
* Reset the allocator (for testing/benchmarking).
|
|
205
|
-
* WARNING: This invalidates ALL buffers created by this strategy.
|
|
206
|
-
*/
|
|
208
|
+
/** Reset invalidates every live handle before allocator offsets are reused. */
|
|
207
209
|
reset(): void {
|
|
210
|
+
for (const root of this.liveRoots) {
|
|
211
|
+
this.invalidateSpanTree(root);
|
|
212
|
+
if (root._traceRoot instanceof WasmTraceRoot) root._traceRoot.invalidate();
|
|
213
|
+
root._traceRoot._topology.release();
|
|
214
|
+
}
|
|
215
|
+
this.liveRoots.clear();
|
|
208
216
|
this.allocator.reset();
|
|
209
217
|
}
|
|
210
218
|
|