@smoothbricks/lmao 0.2.2 → 0.3.0
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/README.md +206 -206
- 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 +33 -18
- 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/typeGuards.d.ts +7 -47
- package/dist/lib/schema/typeGuards.d.ts.map +1 -1
- package/dist/lib/schema/typeGuards.js +7 -123
- 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/traceContext.d.ts.map +1 -1
- package/dist/lib/traceContext.js +1 -4
- 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 +122 -24
- 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/typeGuards.ts +7 -151
- 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/traceContext.ts +1 -6
- 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__/CompositeTracer.test.ts +150 -0
- 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
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it } from 'bun:test';
|
|
2
2
|
import { S as ArrowS, Nanoseconds } from '@smoothbricks/arrow-builder';
|
|
3
|
-
import
|
|
3
|
+
import fc from 'fast-check';
|
|
4
|
+
import { createTestOpMetadata, createTestTraceRoot, TEST_TRACER } from '../../__tests__/test-helpers.js';
|
|
5
|
+
import { defineOpContext } from '../../defineOpContext.js';
|
|
6
|
+
import { type EagerColumnDescriptor, resolveEagerColumns } from '../../physicalLayoutPlan.js';
|
|
7
|
+
import { resolveEntryType, resolveMessage } from '../../resolveMessage.js';
|
|
8
|
+
import { RUNTIME_HINT_ANALYZED_VALID, RUNTIME_HINT_RESULT, RUNTIME_HINT_TAG } from '../../runtimeHint.js';
|
|
4
9
|
import { S } from '../../schema/builder.js';
|
|
5
10
|
import { defineLogSchema } from '../../schema/defineLogSchema.js';
|
|
6
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
ENTRY_TYPE_INFO,
|
|
13
|
+
ENTRY_TYPE_SPAN_EXCEPTION,
|
|
14
|
+
ENTRY_TYPE_SPAN_OK,
|
|
15
|
+
ENTRY_TYPE_SPAN_START,
|
|
16
|
+
} from '../../schema/systemSchema.js';
|
|
17
|
+
import { createSpanBuffer, EMPTY_SCOPE } from '../../spanBuffer.js';
|
|
7
18
|
import { createTraceId } from '../../traceId.js';
|
|
19
|
+
import { iterateSpanChildren, NO_NODE } from '../../traceTopology.js';
|
|
8
20
|
import { createWasmAllocator, type WasmAllocator } from '../wasmAllocator.js';
|
|
21
|
+
import { getWasmPhysicalLayout } from '../wasmPhysicalLayout.js';
|
|
9
22
|
import {
|
|
10
23
|
createWasmChildSpanBuffer,
|
|
11
24
|
createWasmOverflowBuffer,
|
|
@@ -31,6 +44,15 @@ function getColumn<T>(target: object, name: string): T {
|
|
|
31
44
|
return Reflect.get(target, name);
|
|
32
45
|
}
|
|
33
46
|
|
|
47
|
+
function eagerDescriptorBytes(descriptor: EagerColumnDescriptor): Uint8Array {
|
|
48
|
+
const bytes = new Uint8Array(descriptor.words.length * Uint32Array.BYTES_PER_ELEMENT);
|
|
49
|
+
const view = new DataView(bytes.buffer);
|
|
50
|
+
for (let index = 0; index < descriptor.words.length; index++) {
|
|
51
|
+
view.setUint32(index * Uint32Array.BYTES_PER_ELEMENT, descriptor.words[index], true);
|
|
52
|
+
}
|
|
53
|
+
return bytes;
|
|
54
|
+
}
|
|
55
|
+
|
|
34
56
|
describe('WasmSpanBuffer', () => {
|
|
35
57
|
let allocator: WasmAllocator;
|
|
36
58
|
const CAPACITY = 64;
|
|
@@ -40,18 +62,15 @@ describe('WasmSpanBuffer', () => {
|
|
|
40
62
|
allocator = await createWasmAllocator({ capacity: CAPACITY });
|
|
41
63
|
allocator.reset();
|
|
42
64
|
allocator.setThreadId(0, 42); // high=0, low=42 -> thread_id = 42n
|
|
43
|
-
traceRoot = new WasmTraceRoot(allocator, testTraceId('
|
|
65
|
+
traceRoot = new WasmTraceRoot(allocator, testTraceId('trace-123'), TEST_TRACER);
|
|
44
66
|
});
|
|
45
67
|
|
|
46
|
-
function createTestWasmBuffer(
|
|
68
|
+
function createTestWasmBuffer() {
|
|
47
69
|
return createWasmSpanBuffer(
|
|
48
70
|
testSchema,
|
|
49
71
|
{
|
|
50
72
|
allocator,
|
|
51
73
|
capacity: CAPACITY,
|
|
52
|
-
trace_id: overrides.trace_id ? testTraceId(overrides.trace_id) : testTraceId('trace-123'),
|
|
53
|
-
thread_id: overrides.thread_id ?? 42n,
|
|
54
|
-
span_id: overrides.span_id ?? 1,
|
|
55
74
|
},
|
|
56
75
|
traceRoot,
|
|
57
76
|
EMPTY_SCOPE,
|
|
@@ -72,31 +91,150 @@ describe('WasmSpanBuffer', () => {
|
|
|
72
91
|
duration: ArrowS.bigUint64(),
|
|
73
92
|
errorMessage: S.text(),
|
|
74
93
|
});
|
|
94
|
+
const testEagerColumns = resolveEagerColumns(testSchema);
|
|
95
|
+
|
|
96
|
+
const compilerEagerSchema = defineLogSchema({
|
|
97
|
+
provenNumber: S.number(),
|
|
98
|
+
lazyNumber: S.number(),
|
|
99
|
+
provenString: S.category(),
|
|
100
|
+
lazyString: S.category(),
|
|
101
|
+
});
|
|
102
|
+
const compilerEagerContext = defineOpContext({ logSchema: compilerEagerSchema });
|
|
103
|
+
const compilerEagerOp = compilerEagerContext.defineOp('compiler-eager-wasm', (ctx) => ctx.ok(null), undefined, {
|
|
104
|
+
runtimeHint: RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_TAG | RUNTIME_HINT_RESULT | 8,
|
|
105
|
+
eagerColumns: ['provenString', 'provenNumber', 'provenString'],
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
function createCompilerEagerWasmBuffer() {
|
|
109
|
+
return createWasmSpanBuffer(
|
|
110
|
+
compilerEagerSchema,
|
|
111
|
+
{
|
|
112
|
+
allocator,
|
|
113
|
+
capacity: CAPACITY,
|
|
114
|
+
},
|
|
115
|
+
traceRoot,
|
|
116
|
+
EMPTY_SCOPE,
|
|
117
|
+
compilerEagerOp.metadata,
|
|
118
|
+
compilerEagerOp.metadata,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
75
121
|
|
|
76
122
|
describe('getWasmSpanBufferClass', () => {
|
|
77
123
|
it('generates a class constructor', () => {
|
|
78
|
-
const WasmSpanBufferClass = getWasmSpanBufferClass(testSchema);
|
|
124
|
+
const WasmSpanBufferClass = getWasmSpanBufferClass(testSchema, 'mixed', 'current', testEagerColumns);
|
|
79
125
|
expect(typeof WasmSpanBufferClass).toBe('function');
|
|
80
126
|
expect(WasmSpanBufferClass.schema).toBe(testSchema);
|
|
81
127
|
});
|
|
82
128
|
|
|
83
129
|
it('caches classes per schema', () => {
|
|
84
|
-
const class1 = getWasmSpanBufferClass(testSchema);
|
|
85
|
-
const class2 = getWasmSpanBufferClass(testSchema);
|
|
130
|
+
const class1 = getWasmSpanBufferClass(testSchema, 'mixed', 'current', testEagerColumns);
|
|
131
|
+
const class2 = getWasmSpanBufferClass(testSchema, 'mixed', 'current', testEagerColumns);
|
|
86
132
|
expect(class1).toBe(class2);
|
|
87
133
|
});
|
|
88
134
|
|
|
89
135
|
it('creates different classes for different schemas', () => {
|
|
90
136
|
const schema2 = defineLogSchema({ otherField: S.number() });
|
|
91
|
-
const class1 = getWasmSpanBufferClass(testSchema);
|
|
92
|
-
const class2 = getWasmSpanBufferClass(schema2);
|
|
137
|
+
const class1 = getWasmSpanBufferClass(testSchema, 'mixed', 'current', testEagerColumns);
|
|
138
|
+
const class2 = getWasmSpanBufferClass(schema2, 'mixed', 'current', resolveEagerColumns(schema2));
|
|
93
139
|
expect(class1).not.toBe(class2);
|
|
94
140
|
});
|
|
95
141
|
});
|
|
96
142
|
|
|
143
|
+
describe('exact physical layout', () => {
|
|
144
|
+
it('produces aligned, exact, non-overlapping family descriptors for arbitrary capacities', () => {
|
|
145
|
+
fc.assert(
|
|
146
|
+
fc.property(fc.integer({ min: 1, max: 512 }), (capacity) => {
|
|
147
|
+
const layout = getWasmPhysicalLayout(testSchema, capacity, 'mixed', 'current', testEagerColumns);
|
|
148
|
+
expect(layout).toBe(getWasmPhysicalLayout(testSchema, capacity, 'mixed', 'current', testEagerColumns));
|
|
149
|
+
expect(Object.isFrozen(layout)).toBe(true);
|
|
150
|
+
expect(layout.system.timestampOffset).toBe(0);
|
|
151
|
+
expect(layout.system.entryTypeOffset).toBe(capacity * 8);
|
|
152
|
+
const messageIdOffset = (capacity * 9 + 1) & ~1;
|
|
153
|
+
const expectedByteLength = (messageIdOffset + capacity * Uint16Array.BYTES_PER_ELEMENT + 7) & ~7;
|
|
154
|
+
expect(layout.messageLayoutFamily).toBe('mixed');
|
|
155
|
+
expect(layout.messagePhysicalLayout).toBe('current');
|
|
156
|
+
expect(layout.system.messageIdOffset).toBe(messageIdOffset);
|
|
157
|
+
expect('messageIdValidityOffset' in layout.system).toBe(false);
|
|
158
|
+
expect(layout.system.messageDenseIndexOffset).toBeNull();
|
|
159
|
+
expect('messageValidityOffset' in layout.system).toBe(false);
|
|
160
|
+
expect(layout.system.rowHeaderOffset).toBeNull();
|
|
161
|
+
expect(layout.system.byteLength).toBe(expectedByteLength);
|
|
162
|
+
|
|
163
|
+
expect(Object.isFrozen(layout.spanSuperblock)).toBe(true);
|
|
164
|
+
expect(Object.isFrozen(layout.overflowSuperblock)).toBe(true);
|
|
165
|
+
expect(layout.spanSuperblock.identityOffset).toBe(0);
|
|
166
|
+
expect(layout.overflowSuperblock.identityOffset).toBeNull();
|
|
167
|
+
expect(layout.spanSuperblock.systemOffset % layout.system.alignment).toBe(0);
|
|
168
|
+
expect(layout.overflowSuperblock.systemOffset % layout.system.alignment).toBe(0);
|
|
169
|
+
expect(layout.spanSuperblock.byteLength).toBeLessThanOrEqual(layout.spanSuperblock.legacyByteLength);
|
|
170
|
+
expect(layout.overflowSuperblock.byteLength).toBeLessThanOrEqual(layout.overflowSuperblock.legacyByteLength);
|
|
171
|
+
|
|
172
|
+
for (const family of ['u8', 'u32', 'f64'] as const) {
|
|
173
|
+
const slab = layout.slabs[family];
|
|
174
|
+
const columns = layout.columns.filter((column) => column.family === family);
|
|
175
|
+
expect(slab === null).toBe(columns.length === 0);
|
|
176
|
+
if (slab === null) continue;
|
|
177
|
+
|
|
178
|
+
const ranges: Array<readonly [number, number]> = [];
|
|
179
|
+
for (const column of columns) {
|
|
180
|
+
expect(column.valueOffset % column.alignment).toBe(0);
|
|
181
|
+
expect(column.nullByteLength).toBe(Math.ceil(capacity / 8));
|
|
182
|
+
expect(column.valueLength).toBe(capacity * column.byteWidth);
|
|
183
|
+
expect(column.nullOffset + column.nullByteLength).toBeLessThanOrEqual(column.valueOffset);
|
|
184
|
+
expect(column.valueOffset + column.valueLength).toBeLessThanOrEqual(slab.byteLength);
|
|
185
|
+
|
|
186
|
+
const columnRanges = [
|
|
187
|
+
[column.nullOffset, column.nullOffset + column.nullByteLength],
|
|
188
|
+
[column.valueOffset, column.valueOffset + column.valueLength],
|
|
189
|
+
] as const;
|
|
190
|
+
for (const [start, end] of columnRanges) {
|
|
191
|
+
for (const [otherStart, otherEnd] of ranges) {
|
|
192
|
+
expect(end <= otherStart || start >= otherEnd).toBe(true);
|
|
193
|
+
}
|
|
194
|
+
ranges.push([start, end]);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('allocates one packed superblock and no further blocks on numeric writes', () => {
|
|
203
|
+
const allocsBefore = allocator.getAllocCount();
|
|
204
|
+
const buffer = createTestWasmBuffer();
|
|
205
|
+
expect(allocator.getAllocCount() - allocsBefore).toBe(1);
|
|
206
|
+
expect(buffer._allocationPtr).toBe(buffer._identityPtr);
|
|
207
|
+
expect(buffer._systemPtr).toBe(buffer._allocationPtr + buffer._layout.spanSuperblock.systemOffset);
|
|
208
|
+
expect(buffer._allocationByteLength).toBe(buffer._layout.spanSuperblock.byteLength);
|
|
209
|
+
|
|
210
|
+
const ranges: Array<readonly [number, number]> = [
|
|
211
|
+
[buffer._identityPtr, buffer._identityPtr + 128],
|
|
212
|
+
[buffer._systemPtr, buffer._systemPtr + buffer._layout.system.byteLength],
|
|
213
|
+
];
|
|
214
|
+
for (const family of ['u8', 'u32', 'f64'] as const) {
|
|
215
|
+
const slab = buffer._layout.slabs[family];
|
|
216
|
+
if (slab === null) continue;
|
|
217
|
+
const start = buffer._familyPtrs[family];
|
|
218
|
+
const end = start + slab.byteLength;
|
|
219
|
+
expect(start % slab.alignment).toBe(0);
|
|
220
|
+
expect(start).toBe(buffer._allocationPtr + buffer._layout.spanSuperblock.familyOffsets[family]);
|
|
221
|
+
for (const [otherStart, otherEnd] of ranges) {
|
|
222
|
+
expect(end <= otherStart || start >= otherEnd).toBe(true);
|
|
223
|
+
}
|
|
224
|
+
ranges.push([start, end]);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const count = getMethod<[idx: number, val: number], WasmSpanBufferInstance>(buffer, 'count');
|
|
228
|
+
const isAdmin = getMethod<[idx: number, val: boolean], WasmSpanBufferInstance>(buffer, 'isAdmin');
|
|
229
|
+
count(3, 42);
|
|
230
|
+
isAdmin(4, true);
|
|
231
|
+
expect(allocator.getAllocCount() - allocsBefore).toBe(1);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
97
235
|
describe('instance creation', () => {
|
|
98
236
|
it('creates instance with correct identity', () => {
|
|
99
|
-
const buffer = createTestWasmBuffer(
|
|
237
|
+
const buffer = createTestWasmBuffer();
|
|
100
238
|
|
|
101
239
|
expect(buffer.trace_id).toBe(testTraceId('trace-123'));
|
|
102
240
|
expect(buffer.thread_id).toBe(42n);
|
|
@@ -106,14 +244,60 @@ describe('WasmSpanBuffer', () => {
|
|
|
106
244
|
expect(buffer._hasParent).toBe(false);
|
|
107
245
|
});
|
|
108
246
|
|
|
247
|
+
it('consumes native lifecycle initialization without restamping row 0', () => {
|
|
248
|
+
const buffer = createTestWasmBuffer();
|
|
249
|
+
const entryTypes = buffer.entry_type;
|
|
250
|
+
if (entryTypes === undefined) throw new Error('missing entry types');
|
|
251
|
+
|
|
252
|
+
expect(buffer._spanStartedAtAllocation).toBe(true);
|
|
253
|
+
expect(buffer._writeIndex).toBe(2);
|
|
254
|
+
expect(entryTypes[0]).toBe(ENTRY_TYPE_SPAN_START);
|
|
255
|
+
expect(entryTypes[1]).toBe(ENTRY_TYPE_SPAN_EXCEPTION);
|
|
256
|
+
buffer.timestamp[0] = 123_456_789n;
|
|
257
|
+
|
|
258
|
+
traceRoot.writeSpanStart(buffer, 'prestarted-span');
|
|
259
|
+
|
|
260
|
+
expect(buffer._spanStartedAtAllocation).toBe(false);
|
|
261
|
+
expect(buffer.timestamp[0]).toBe(123_456_789n);
|
|
262
|
+
const messages = buffer.message_values;
|
|
263
|
+
if (messages === undefined) throw new Error('missing messages');
|
|
264
|
+
expect(messages[0]).toBe('prestarted-span');
|
|
265
|
+
expect(buffer._writeIndex).toBe(2);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('uses each buffer capacity for native lifecycle writes', () => {
|
|
269
|
+
const seededCapacity = 6;
|
|
270
|
+
const metadata = createTestOpMetadata();
|
|
271
|
+
const buffer = createWasmSpanBuffer(
|
|
272
|
+
testSchema,
|
|
273
|
+
{ allocator, capacity: seededCapacity },
|
|
274
|
+
traceRoot,
|
|
275
|
+
EMPTY_SCOPE,
|
|
276
|
+
metadata,
|
|
277
|
+
metadata,
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
traceRoot.writeSpanStart(buffer, 'seeded-capacity');
|
|
281
|
+
const row = traceRoot.writeLogEntry(buffer, ENTRY_TYPE_INFO);
|
|
282
|
+
traceRoot.writeSpanEnd(buffer, ENTRY_TYPE_SPAN_OK);
|
|
283
|
+
|
|
284
|
+
expect(buffer._capacity).toBe(seededCapacity);
|
|
285
|
+
expect(row).toBe(2);
|
|
286
|
+
expect(buffer.entry_type?.[0]).toBe(ENTRY_TYPE_SPAN_START);
|
|
287
|
+
expect(buffer.entry_type?.[1]).toBe(ENTRY_TYPE_SPAN_OK);
|
|
288
|
+
expect(buffer.entry_type?.[2]).toBe(ENTRY_TYPE_INFO);
|
|
289
|
+
expect(buffer.timestamp[1]).toBeGreaterThan(0n);
|
|
290
|
+
expect(buffer.timestamp[2]).toBeGreaterThan(0n);
|
|
291
|
+
});
|
|
292
|
+
|
|
109
293
|
it('creates instance with parent identity via child buffer', () => {
|
|
110
294
|
// Parent identity is now set by linking buffers, not via opts
|
|
111
295
|
// Create parent first, then create child that references it
|
|
112
|
-
const parent = createTestWasmBuffer(
|
|
296
|
+
const parent = createTestWasmBuffer();
|
|
113
297
|
|
|
114
298
|
const child = createWasmChildSpanBuffer(
|
|
115
299
|
parent,
|
|
116
|
-
{ allocator, capacity: CAPACITY
|
|
300
|
+
{ allocator, capacity: CAPACITY },
|
|
117
301
|
traceRoot,
|
|
118
302
|
EMPTY_SCOPE,
|
|
119
303
|
createTestOpMetadata(),
|
|
@@ -129,17 +313,20 @@ describe('WasmSpanBuffer', () => {
|
|
|
129
313
|
it('allocates system block from WASM', () => {
|
|
130
314
|
const beforeAllocs = allocator.getAllocCount();
|
|
131
315
|
|
|
132
|
-
createTestWasmBuffer(
|
|
316
|
+
createTestWasmBuffer();
|
|
133
317
|
|
|
134
318
|
// Should have allocated at least the system block
|
|
135
319
|
expect(allocator.getAllocCount()).toBeGreaterThan(beforeAllocs);
|
|
136
320
|
});
|
|
137
321
|
|
|
138
322
|
it('initializes tree structure', () => {
|
|
139
|
-
const buffer = createTestWasmBuffer(
|
|
323
|
+
const buffer = createTestWasmBuffer();
|
|
324
|
+
traceRoot._topology.registerRoot(buffer);
|
|
140
325
|
|
|
141
326
|
expect(buffer._parent).toBeNull();
|
|
142
|
-
expect(buffer.
|
|
327
|
+
expect(buffer._nodeIndex).toBe(traceRoot._topology.root);
|
|
328
|
+
expect(traceRoot._topology.buffers[buffer._nodeIndex]).toBe(buffer);
|
|
329
|
+
expect(traceRoot._topology.firstChild[buffer._nodeIndex]).toBe(NO_NODE);
|
|
143
330
|
expect(buffer._overflow).toBeNull();
|
|
144
331
|
});
|
|
145
332
|
});
|
|
@@ -148,7 +335,7 @@ describe('WasmSpanBuffer', () => {
|
|
|
148
335
|
let buffer: WasmSpanBufferInstance;
|
|
149
336
|
|
|
150
337
|
beforeEach(() => {
|
|
151
|
-
buffer = createTestWasmBuffer(
|
|
338
|
+
buffer = createTestWasmBuffer();
|
|
152
339
|
});
|
|
153
340
|
|
|
154
341
|
it('provides timestamp view into WASM memory', () => {
|
|
@@ -159,6 +346,7 @@ describe('WasmSpanBuffer', () => {
|
|
|
159
346
|
|
|
160
347
|
it('provides entry_type view into WASM memory', () => {
|
|
161
348
|
const entryType = buffer.entry_type;
|
|
349
|
+
if (entryType === undefined) throw new Error('Expected split entry-type lane');
|
|
162
350
|
expect(entryType).toBeInstanceOf(Uint8Array);
|
|
163
351
|
expect(entryType.length).toBe(CAPACITY);
|
|
164
352
|
});
|
|
@@ -171,17 +359,55 @@ describe('WasmSpanBuffer', () => {
|
|
|
171
359
|
|
|
172
360
|
it('can write to entry_type array', () => {
|
|
173
361
|
const entryType = buffer.entry_type;
|
|
362
|
+
if (entryType === undefined) throw new Error('Expected split entry-type lane');
|
|
174
363
|
entryType[0] = 1; // SPAN_START
|
|
175
364
|
entryType[1] = 2; // SPAN_OK
|
|
176
|
-
expect(buffer
|
|
177
|
-
expect(buffer
|
|
365
|
+
expect(resolveEntryType(buffer, 0)).toBe(1);
|
|
366
|
+
expect(resolveEntryType(buffer, 1)).toBe(2);
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('reuses canonical typed views while memory is stable', () => {
|
|
370
|
+
const timestamp = buffer.timestamp;
|
|
371
|
+
const entryType = buffer.entry_type;
|
|
372
|
+
const identity = buffer._identity;
|
|
373
|
+
const countValues = getColumn<Float64Array>(buffer, 'count_values');
|
|
374
|
+
const countNulls = getColumn<Uint8Array>(buffer, 'count_nulls');
|
|
375
|
+
const count = getMethod<[idx: number, val: number], WasmSpanBufferInstance>(buffer, 'count');
|
|
376
|
+
|
|
377
|
+
count(5, 999);
|
|
378
|
+
|
|
379
|
+
expect(buffer.timestamp).toBe(timestamp);
|
|
380
|
+
expect(buffer.entry_type).toBe(entryType);
|
|
381
|
+
expect(buffer._identity).toBe(identity);
|
|
382
|
+
expect(getColumn<Float64Array>(buffer, 'count_values')).toBe(countValues);
|
|
383
|
+
expect(getColumn<Uint8Array>(buffer, 'count_nulls')).toBe(countNulls);
|
|
384
|
+
expect(countValues[5]).toBe(999);
|
|
178
385
|
});
|
|
179
386
|
|
|
180
|
-
it('
|
|
181
|
-
buffer.timestamp[
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
387
|
+
it('rebuilds every canonical view once after memory growth and preserves data', () => {
|
|
388
|
+
buffer.timestamp[3] = 123n;
|
|
389
|
+
const count = getMethod<[idx: number, val: number], WasmSpanBufferInstance>(buffer, 'count');
|
|
390
|
+
count(4, 456);
|
|
391
|
+
const timestampBefore = buffer.timestamp;
|
|
392
|
+
const identityBefore = buffer._identity;
|
|
393
|
+
const countBefore = getColumn<Float64Array>(buffer, 'count_values');
|
|
394
|
+
const versionBefore = buffer._descriptor.memoryVersion;
|
|
395
|
+
|
|
396
|
+
const growthAllocation = allocator.allocExact(allocator.memory.buffer.byteLength, 8);
|
|
397
|
+
expect(growthAllocation).toBeGreaterThan(0);
|
|
398
|
+
const timestampAfter = buffer.timestamp;
|
|
399
|
+
const identityAfter = buffer._identity;
|
|
400
|
+
const countAfter = getColumn<Float64Array>(buffer, 'count_values');
|
|
401
|
+
|
|
402
|
+
expect(buffer._descriptor.memoryVersion).toBeGreaterThan(versionBefore);
|
|
403
|
+
expect(timestampAfter).not.toBe(timestampBefore);
|
|
404
|
+
expect(identityAfter).not.toBe(identityBefore);
|
|
405
|
+
expect(countAfter).not.toBe(countBefore);
|
|
406
|
+
expect(buffer.timestamp).toBe(timestampAfter);
|
|
407
|
+
expect(buffer._identity).toBe(identityAfter);
|
|
408
|
+
expect(getColumn<Float64Array>(buffer, 'count_values')).toBe(countAfter);
|
|
409
|
+
expect(timestampAfter[3]).toBe(123n);
|
|
410
|
+
expect(countAfter[4]).toBe(456);
|
|
185
411
|
});
|
|
186
412
|
|
|
187
413
|
it('exposes _spanStartTime from row 0', () => {
|
|
@@ -215,17 +441,17 @@ describe('WasmSpanBuffer', () => {
|
|
|
215
441
|
let buffer: WasmSpanBufferInstance;
|
|
216
442
|
|
|
217
443
|
beforeEach(() => {
|
|
218
|
-
buffer = createTestWasmBuffer(
|
|
444
|
+
buffer = createTestWasmBuffer();
|
|
219
445
|
});
|
|
220
446
|
|
|
221
447
|
it('can write message values', () => {
|
|
222
448
|
buffer.message(0, 'span-start message');
|
|
223
449
|
buffer.message(1, 'span-end message');
|
|
224
450
|
buffer.message(2, 'log entry');
|
|
225
|
-
|
|
226
|
-
expect(buffer
|
|
227
|
-
expect(buffer
|
|
228
|
-
expect(buffer
|
|
451
|
+
expect('message_nulls' in buffer).toBe(false);
|
|
452
|
+
expect(resolveMessage(buffer, 0)).toBe('span-start message');
|
|
453
|
+
expect(resolveMessage(buffer, 1)).toBe('span-end message');
|
|
454
|
+
expect(resolveMessage(buffer, 2)).toBe('log entry');
|
|
229
455
|
});
|
|
230
456
|
|
|
231
457
|
it('returns this for chaining', () => {
|
|
@@ -238,7 +464,7 @@ describe('WasmSpanBuffer', () => {
|
|
|
238
464
|
let buffer: WasmSpanBufferInstance;
|
|
239
465
|
|
|
240
466
|
beforeEach(() => {
|
|
241
|
-
buffer = createTestWasmBuffer(
|
|
467
|
+
buffer = createTestWasmBuffer();
|
|
242
468
|
});
|
|
243
469
|
|
|
244
470
|
it('userId column starts undefined', () => {
|
|
@@ -254,6 +480,19 @@ describe('WasmSpanBuffer', () => {
|
|
|
254
480
|
expect(buffer.getNullsIfAllocated('userId')).toBeDefined();
|
|
255
481
|
});
|
|
256
482
|
|
|
483
|
+
it('allocates lazy storage for transformer-style direct writes', () => {
|
|
484
|
+
const userIdNulls = getColumn<Uint8Array>(buffer, 'userId_nulls');
|
|
485
|
+
const userIdValues = getColumn<string[]>(buffer, 'userId_values');
|
|
486
|
+
|
|
487
|
+
userIdNulls[0] |= 1;
|
|
488
|
+
userIdValues[0] = 'direct-write';
|
|
489
|
+
|
|
490
|
+
expect(buffer.getColumnIfAllocated('userId')).toBe(userIdValues);
|
|
491
|
+
expect(buffer.getNullsIfAllocated('userId')).toBe(userIdNulls);
|
|
492
|
+
expect(userIdValues[0]).toBe('direct-write');
|
|
493
|
+
expect(userIdNulls[0] & 1).toBe(1);
|
|
494
|
+
});
|
|
495
|
+
|
|
257
496
|
it('writes values to category column', () => {
|
|
258
497
|
const userId = getMethod<[idx: number, val: string], WasmSpanBufferInstance>(buffer, 'userId');
|
|
259
498
|
|
|
@@ -304,18 +543,26 @@ describe('WasmSpanBuffer', () => {
|
|
|
304
543
|
let buffer: WasmSpanBufferInstance;
|
|
305
544
|
|
|
306
545
|
beforeEach(() => {
|
|
307
|
-
buffer = createTestWasmBuffer(
|
|
546
|
+
buffer = createTestWasmBuffer();
|
|
308
547
|
});
|
|
309
548
|
|
|
310
|
-
it('
|
|
311
|
-
|
|
549
|
+
it('reserves numeric bytes in the family slab without materializing the lazy lane', () => {
|
|
550
|
+
const countIndex = testSchema._columnNames.indexOf('count');
|
|
551
|
+
if (countIndex < 0) throw new Error('missing count schema field');
|
|
552
|
+
expect(buffer._layout.columns.some((column) => column.name === 'count')).toBe(true);
|
|
553
|
+
expect(buffer.isColumnAllocated(countIndex)).toBe(false);
|
|
554
|
+
expect(buffer.getColumnIfAllocated('count')).toBeUndefined();
|
|
555
|
+
expect(Reflect.get(buffer, '_count_values')).toBeUndefined();
|
|
556
|
+
expect(Reflect.get(buffer, '_count_nulls')).toBeUndefined();
|
|
312
557
|
});
|
|
313
558
|
|
|
314
|
-
it('
|
|
559
|
+
it('writes without allocating another block', () => {
|
|
315
560
|
const count = getMethod<[idx: number, val: number], WasmSpanBufferInstance>(buffer, 'count');
|
|
561
|
+
const allocsBefore = allocator.getAllocCount();
|
|
316
562
|
count(0, 42);
|
|
317
|
-
|
|
318
|
-
expect(buffer.
|
|
563
|
+
expect(allocator.getAllocCount()).toBe(allocsBefore);
|
|
564
|
+
expect(buffer.getColumnIfAllocated('count')).toBeInstanceOf(Float64Array);
|
|
565
|
+
expect(buffer.getNullsIfAllocated('count')).toBeInstanceOf(Uint8Array);
|
|
319
566
|
});
|
|
320
567
|
|
|
321
568
|
it('writes to numeric column', () => {
|
|
@@ -339,37 +586,135 @@ describe('WasmSpanBuffer', () => {
|
|
|
339
586
|
|
|
340
587
|
describe('eager numeric columns', () => {
|
|
341
588
|
it('statusCode column is pre-allocated', () => {
|
|
342
|
-
const buffer = createTestWasmBuffer(
|
|
589
|
+
const buffer = createTestWasmBuffer();
|
|
343
590
|
|
|
344
591
|
// statusCode is at index 3 and marked eager
|
|
345
592
|
expect(buffer.isColumnAllocated(3)).toBe(true);
|
|
346
593
|
});
|
|
347
594
|
});
|
|
348
595
|
|
|
349
|
-
describe('
|
|
350
|
-
it('
|
|
351
|
-
const
|
|
596
|
+
describe('compiler-proven eager columns', () => {
|
|
597
|
+
it('shares exact frozen descriptor bytes and eager storage across root, child, and overflow', () => {
|
|
598
|
+
const descriptor = compilerEagerOp.callsitePlan.eagerColumns;
|
|
599
|
+
const planSchema = compilerEagerOp.callsitePlan.schema;
|
|
600
|
+
const expectedWords = new Array<number>(Math.ceil(planSchema._columnNames.length / 32)).fill(0);
|
|
601
|
+
for (const name of ['provenNumber', 'provenString']) {
|
|
602
|
+
const ordinal = planSchema._columnNames.indexOf(name);
|
|
603
|
+
if (ordinal < 0) throw new Error(`missing compiler eager schema field ${name}`);
|
|
604
|
+
expectedWords[ordinal >>> 5] = (expectedWords[ordinal >>> 5] | (1 << (ordinal & 31))) >>> 0;
|
|
605
|
+
}
|
|
606
|
+
while (expectedWords.length > 0 && expectedWords[expectedWords.length - 1] === 0) expectedWords.pop();
|
|
352
607
|
|
|
608
|
+
expect(descriptor.names).toEqual(['provenNumber', 'provenString']);
|
|
609
|
+
expect(descriptor.words).toEqual(expectedWords);
|
|
610
|
+
expect(eagerDescriptorBytes(descriptor).byteLength).toBe(descriptor.words.length * 4);
|
|
611
|
+
expect(Object.isFrozen(descriptor)).toBe(true);
|
|
612
|
+
expect(Object.isFrozen(descriptor.names)).toBe(true);
|
|
613
|
+
expect(Object.isFrozen(descriptor.words)).toBe(true);
|
|
614
|
+
expect(compilerEagerOp.callsitePlan.wasmLayout.eagerColumns).toBe(descriptor);
|
|
615
|
+
|
|
616
|
+
const root = createCompilerEagerWasmBuffer();
|
|
617
|
+
const child = createWasmChildSpanBuffer(
|
|
618
|
+
root,
|
|
619
|
+
{ allocator, capacity: CAPACITY },
|
|
620
|
+
traceRoot,
|
|
621
|
+
EMPTY_SCOPE,
|
|
622
|
+
compilerEagerOp.metadata,
|
|
623
|
+
compilerEagerOp.metadata,
|
|
624
|
+
);
|
|
625
|
+
const overflow = createWasmOverflowBuffer(
|
|
626
|
+
child,
|
|
627
|
+
traceRoot,
|
|
628
|
+
EMPTY_SCOPE,
|
|
629
|
+
compilerEagerOp.metadata,
|
|
630
|
+
compilerEagerOp.metadata,
|
|
631
|
+
);
|
|
632
|
+
|
|
633
|
+
for (const buffer of [root, child, overflow]) {
|
|
634
|
+
expect(buffer._layout.eagerColumns).toBe(descriptor);
|
|
635
|
+
for (const name of ['provenNumber', 'provenString']) {
|
|
636
|
+
expect(Object.hasOwn(buffer, `_${name}_values`)).toBe(true);
|
|
637
|
+
expect(Object.hasOwn(buffer, `_${name}_nulls`)).toBe(true);
|
|
638
|
+
expect(Reflect.get(buffer, `_${name}_values`)).toBeDefined();
|
|
639
|
+
expect(Reflect.get(buffer, `_${name}_nulls`)).toBeInstanceOf(Uint8Array);
|
|
640
|
+
}
|
|
641
|
+
for (const name of ['lazyNumber', 'lazyString']) {
|
|
642
|
+
expect(Reflect.get(buffer, `_${name}_values`)).toBeUndefined();
|
|
643
|
+
expect(Reflect.get(buffer, `_${name}_nulls`)).toBeUndefined();
|
|
644
|
+
expect(buffer.getColumnIfAllocated(name)).toBeUndefined();
|
|
645
|
+
expect(buffer.getNullsIfAllocated(name)).toBeUndefined();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
expect(child._parent).toBe(root);
|
|
649
|
+
expect(overflow._parent).toBe(root);
|
|
650
|
+
expect(overflow._identityPtr).toBe(child._identityPtr);
|
|
651
|
+
expect(overflow._descriptor.layout).toBe(child._descriptor.layout);
|
|
652
|
+
|
|
653
|
+
root.provenNumber(0, 73);
|
|
654
|
+
root.provenNumber(1, null);
|
|
655
|
+
root.provenString(2, 'wasm-value');
|
|
656
|
+
overflow.provenNumber(3, null);
|
|
657
|
+
|
|
658
|
+
const jsBuffer = createSpanBuffer(
|
|
659
|
+
planSchema,
|
|
660
|
+
createTestTraceRoot('compiler-eager-js'),
|
|
661
|
+
compilerEagerOp.metadata,
|
|
662
|
+
CAPACITY,
|
|
663
|
+
compilerEagerOp.callsitePlan.SpanBufferClass,
|
|
664
|
+
);
|
|
665
|
+
jsBuffer.provenNumber(0, 73);
|
|
666
|
+
jsBuffer.provenNumber(1, null);
|
|
667
|
+
jsBuffer.provenString(2, 'wasm-value');
|
|
668
|
+
|
|
669
|
+
for (const name of ['provenNumber', 'provenString']) {
|
|
670
|
+
const wasmValues = root.getColumnIfAllocated(name);
|
|
671
|
+
const jsValues = jsBuffer.getColumnIfAllocated(name);
|
|
672
|
+
const wasmNulls = root.getNullsIfAllocated(name);
|
|
673
|
+
const jsNulls = jsBuffer.getNullsIfAllocated(name);
|
|
674
|
+
if (!wasmValues || !jsValues || !wasmNulls || !jsNulls) {
|
|
675
|
+
throw new Error(`missing eager JS/WASM parity storage for ${name}`);
|
|
676
|
+
}
|
|
677
|
+
for (const row of [0, 1, 2, 3]) expect(wasmValues[row]).toEqual(jsValues[row]);
|
|
678
|
+
expect([...wasmNulls]).toEqual([...jsNulls]);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const lazyString = getMethod<[index: number, value: string], WasmSpanBufferInstance>(root, 'lazyString');
|
|
682
|
+
lazyString(4, 'first lazy write');
|
|
683
|
+
expect(root.getColumnIfAllocated('lazyString')?.[4]).toBe('first lazy write');
|
|
684
|
+
const lazyStringNulls = root.getNullsIfAllocated('lazyString');
|
|
685
|
+
if (!lazyStringNulls) throw new Error('missing lazy string null bitmap after first write');
|
|
686
|
+
expect(lazyStringNulls[0] & 0b00010000).toBe(0b00010000);
|
|
687
|
+
|
|
688
|
+
const schemaEager = createTestWasmBuffer();
|
|
689
|
+
expect(schemaEager.getColumnIfAllocated('statusCode')).toBeDefined();
|
|
690
|
+
expect(schemaEager.getNullsIfAllocated('statusCode')).toBeUndefined();
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
describe('free()', () => {
|
|
695
|
+
it('releases its owned superblock once', () => {
|
|
696
|
+
const buffer = createTestWasmBuffer();
|
|
353
697
|
const freesBefore = allocator.getFreeCount();
|
|
698
|
+
|
|
354
699
|
buffer.free();
|
|
355
700
|
|
|
356
|
-
expect(allocator.getFreeCount()).
|
|
701
|
+
expect(allocator.getFreeCount() - freesBefore).toBe(1);
|
|
702
|
+
expect(buffer._descriptor.state).toBe('freed');
|
|
357
703
|
});
|
|
358
704
|
|
|
359
|
-
it('
|
|
360
|
-
const buffer = createTestWasmBuffer(
|
|
361
|
-
|
|
362
|
-
// Write to lazy columns to allocate them
|
|
705
|
+
it('is idempotent and rejects every stale accessor and writer', () => {
|
|
706
|
+
const buffer = createTestWasmBuffer();
|
|
363
707
|
const count = getMethod<[idx: number, val: number], WasmSpanBufferInstance>(buffer, 'count');
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
isAdmin(0, true);
|
|
708
|
+
buffer.free();
|
|
709
|
+
const freesAfterFirstRelease = allocator.getFreeCount();
|
|
367
710
|
|
|
368
|
-
const freesBefore = allocator.getFreeCount();
|
|
369
711
|
buffer.free();
|
|
370
712
|
|
|
371
|
-
|
|
372
|
-
expect(
|
|
713
|
+
expect(allocator.getFreeCount()).toBe(freesAfterFirstRelease);
|
|
714
|
+
expect(() => buffer.timestamp).toThrow(/generation .* released/);
|
|
715
|
+
expect(() => buffer.entry_type).toThrow(/generation .* released/);
|
|
716
|
+
expect(() => buffer._identity).toThrow(/generation .* released/);
|
|
717
|
+
expect(() => count(0, 42)).toThrow(/generation .* released/);
|
|
373
718
|
});
|
|
374
719
|
});
|
|
375
720
|
|
|
@@ -378,26 +723,31 @@ describe('WasmSpanBuffer', () => {
|
|
|
378
723
|
// thread_id is global in WASM header, shared by parent and child
|
|
379
724
|
allocator.setThreadId(0, 1); // thread_id = 1n
|
|
380
725
|
|
|
381
|
-
const parent = createTestWasmBuffer(
|
|
726
|
+
const parent = createTestWasmBuffer();
|
|
727
|
+
traceRoot._topology.registerRoot(parent);
|
|
382
728
|
|
|
383
729
|
const child = createWasmChildSpanBuffer(
|
|
384
730
|
parent,
|
|
385
|
-
{ allocator, capacity: CAPACITY
|
|
731
|
+
{ allocator, capacity: CAPACITY },
|
|
386
732
|
traceRoot,
|
|
387
733
|
EMPTY_SCOPE,
|
|
388
734
|
createTestOpMetadata(),
|
|
389
735
|
createTestOpMetadata({ name: 'child-span', line: 0 }),
|
|
390
736
|
);
|
|
391
737
|
|
|
392
|
-
|
|
393
|
-
parent._children.push(child);
|
|
738
|
+
traceRoot._topology.registerChild(parent, child);
|
|
394
739
|
|
|
395
740
|
expect(child._parent).toBe(parent);
|
|
396
|
-
expect(parent
|
|
741
|
+
expect(Array.from(iterateSpanChildren(parent))).toEqual([child]);
|
|
397
742
|
expect(child.trace_id).toBe(testTraceId('trace-123'));
|
|
398
743
|
// Parent and child share thread_id from global header
|
|
399
744
|
expect(child.parent_thread_id).toBe(1n);
|
|
400
745
|
expect(child.parent_span_id).toBe(1);
|
|
746
|
+
expect(child._identityPtr).not.toBe(parent._identityPtr);
|
|
747
|
+
expect(child._identityOwner).toBe(true);
|
|
748
|
+
expect(child._descriptor.kind).toBe('child');
|
|
749
|
+
expect(child._descriptor.parent).toBe(parent._descriptor);
|
|
750
|
+
expect(child._descriptor.generation).toBeGreaterThan(parent._descriptor.generation);
|
|
401
751
|
});
|
|
402
752
|
});
|
|
403
753
|
|
|
@@ -406,7 +756,8 @@ describe('WasmSpanBuffer', () => {
|
|
|
406
756
|
// thread_id is global in WASM header
|
|
407
757
|
allocator.setThreadId(0, 1); // thread_id = 1n
|
|
408
758
|
|
|
409
|
-
const buffer = createTestWasmBuffer(
|
|
759
|
+
const buffer = createTestWasmBuffer();
|
|
760
|
+
const allocsBefore = allocator.getAllocCount();
|
|
410
761
|
|
|
411
762
|
const overflow = createWasmOverflowBuffer(
|
|
412
763
|
buffer,
|
|
@@ -415,14 +766,19 @@ describe('WasmSpanBuffer', () => {
|
|
|
415
766
|
createTestOpMetadata(),
|
|
416
767
|
createTestOpMetadata(),
|
|
417
768
|
);
|
|
769
|
+
expect(allocator.getAllocCount() - allocsBefore).toBe(1);
|
|
418
770
|
|
|
419
771
|
expect(buffer._overflow).toBe(overflow);
|
|
420
772
|
expect(overflow._parent).toBe(buffer._parent); // Same parent (null for root)
|
|
421
773
|
expect(overflow.trace_id).toBe(testTraceId('trace-123'));
|
|
422
774
|
expect(overflow.thread_id).toBe(1n);
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
expect(overflow.
|
|
775
|
+
expect(overflow.span_id).toBe(buffer.span_id);
|
|
776
|
+
expect(overflow._identityPtr).toBe(buffer._identityPtr);
|
|
777
|
+
expect(overflow._identityOwner).toBe(false);
|
|
778
|
+
expect(overflow._descriptor.kind).toBe('overflow');
|
|
779
|
+
expect(overflow._descriptor.parent).toBeUndefined();
|
|
780
|
+
expect(buffer._descriptor.overflow).toBe(overflow._descriptor);
|
|
781
|
+
expect(overflow._descriptor.generation).toBeGreaterThan(buffer._descriptor.generation);
|
|
426
782
|
});
|
|
427
783
|
});
|
|
428
784
|
|
|
@@ -431,7 +787,7 @@ describe('WasmSpanBuffer', () => {
|
|
|
431
787
|
// thread_id is global in WASM header
|
|
432
788
|
allocator.setThreadId(0, 1); // thread_id = 1n
|
|
433
789
|
|
|
434
|
-
const buffer = createTestWasmBuffer(
|
|
790
|
+
const buffer = createTestWasmBuffer();
|
|
435
791
|
|
|
436
792
|
// Get custom inspect
|
|
437
793
|
const inspectSymbol = Symbol.for('nodejs.util.inspect.custom');
|