@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,405 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { Column, type Table } from '@uwdata/flechette';
|
|
5
|
+
import { getVocabularyDictionaryPrefix } from '../arrow/vocabularyDictionary.js';
|
|
6
|
+
import {
|
|
7
|
+
convertSpanTreeToLeasedArrowTable,
|
|
8
|
+
convertToArrowTable,
|
|
9
|
+
convertToLeasedArrowTable,
|
|
10
|
+
} from '../convertToArrow.js';
|
|
11
|
+
import { defineOpContext } from '../defineOpContext.js';
|
|
12
|
+
import { resolveMessage } from '../resolveMessage.js';
|
|
13
|
+
import {
|
|
14
|
+
RUNTIME_HINT_ANALYZED_VALID,
|
|
15
|
+
RUNTIME_HINT_LOG,
|
|
16
|
+
RUNTIME_HINT_MESSAGE_LAYOUT_MIXED,
|
|
17
|
+
RUNTIME_HINT_MESSAGE_PHYSICAL_PACKED,
|
|
18
|
+
RUNTIME_HINT_RESULT,
|
|
19
|
+
} from '../runtimeHint.js';
|
|
20
|
+
import { S } from '../schema/builder.js';
|
|
21
|
+
import { defineLogSchema } from '../schema/defineLogSchema.js';
|
|
22
|
+
import { TestTracer } from '../tracers/TestTracer.js';
|
|
23
|
+
import type { SpanBuffer } from '../types.js';
|
|
24
|
+
import { getVocabularyGeneration, registerVocabularyFragment, type VocabularyFragment } from '../vocabularyRegistry.js';
|
|
25
|
+
import { createTestTracerOptions } from './test-helpers.js';
|
|
26
|
+
|
|
27
|
+
const encoder = new TextEncoder();
|
|
28
|
+
|
|
29
|
+
function encodeRecord(text: string): Uint8Array {
|
|
30
|
+
const textBytes = encoder.encode(text);
|
|
31
|
+
const record = new Uint8Array(4 + textBytes.length + 2);
|
|
32
|
+
new DataView(record.buffer).setUint32(0, textBytes.length, true);
|
|
33
|
+
record.set(textBytes, 4);
|
|
34
|
+
return record;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function fragmentHash(fragment: Omit<VocabularyFragment, 'contentHash'>): string {
|
|
38
|
+
const algorithm = encoder.encode(fragment.idAlgorithm);
|
|
39
|
+
const byteLength =
|
|
40
|
+
1 +
|
|
41
|
+
2 +
|
|
42
|
+
algorithm.length +
|
|
43
|
+
4 +
|
|
44
|
+
fragment.ids.length * 4 +
|
|
45
|
+
4 +
|
|
46
|
+
fragment.kindTags.length +
|
|
47
|
+
4 +
|
|
48
|
+
fragment.utf8.length +
|
|
49
|
+
4 +
|
|
50
|
+
fragment.offsets.length * 4;
|
|
51
|
+
const bytes = new Uint8Array(byteLength);
|
|
52
|
+
const view = new DataView(bytes.buffer);
|
|
53
|
+
let offset = 0;
|
|
54
|
+
bytes[offset++] = fragment.schemaVersion;
|
|
55
|
+
view.setUint16(offset, algorithm.length, true);
|
|
56
|
+
offset += 2;
|
|
57
|
+
bytes.set(algorithm, offset);
|
|
58
|
+
offset += algorithm.length;
|
|
59
|
+
view.setUint32(offset, fragment.ids.length, true);
|
|
60
|
+
offset += 4;
|
|
61
|
+
for (const id of fragment.ids) {
|
|
62
|
+
view.setUint32(offset, id, true);
|
|
63
|
+
offset += 4;
|
|
64
|
+
}
|
|
65
|
+
view.setUint32(offset, fragment.kindTags.length, true);
|
|
66
|
+
offset += 4;
|
|
67
|
+
bytes.set(fragment.kindTags, offset);
|
|
68
|
+
offset += fragment.kindTags.length;
|
|
69
|
+
view.setUint32(offset, fragment.utf8.length, true);
|
|
70
|
+
offset += 4;
|
|
71
|
+
bytes.set(fragment.utf8, offset);
|
|
72
|
+
offset += fragment.utf8.length;
|
|
73
|
+
view.setUint32(offset, fragment.offsets.length, true);
|
|
74
|
+
offset += 4;
|
|
75
|
+
for (const boundary of fragment.offsets) {
|
|
76
|
+
view.setInt32(offset, boundary, true);
|
|
77
|
+
offset += 4;
|
|
78
|
+
}
|
|
79
|
+
return createHash('sha256').update(bytes).digest('hex');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function makeFragment(texts: readonly string[]): VocabularyFragment {
|
|
83
|
+
const records = texts.map(encodeRecord);
|
|
84
|
+
const offsets = new Int32Array(records.length + 1);
|
|
85
|
+
const ids = new Uint32Array(records.length);
|
|
86
|
+
let byteLength = 0;
|
|
87
|
+
for (let ordinal = 0; ordinal < records.length; ordinal++) {
|
|
88
|
+
const record = records[ordinal];
|
|
89
|
+
byteLength += record.length;
|
|
90
|
+
offsets[ordinal + 1] = byteLength;
|
|
91
|
+
const digest = createHash('sha256').update(Uint8Array.of(1)).update(record).digest();
|
|
92
|
+
ids[ordinal] = (digest[0] << 16) | (digest[1] << 8) | digest[2];
|
|
93
|
+
}
|
|
94
|
+
const utf8 = new Uint8Array(byteLength);
|
|
95
|
+
let offset = 0;
|
|
96
|
+
for (const record of records) {
|
|
97
|
+
utf8.set(record, offset);
|
|
98
|
+
offset += record.length;
|
|
99
|
+
}
|
|
100
|
+
const fragment: Omit<VocabularyFragment, 'contentHash'> = {
|
|
101
|
+
schemaVersion: 1,
|
|
102
|
+
idAlgorithm: 'sha256-24-v1',
|
|
103
|
+
ids,
|
|
104
|
+
kindTags: new Uint8Array(texts.length).fill(1),
|
|
105
|
+
utf8,
|
|
106
|
+
offsets,
|
|
107
|
+
};
|
|
108
|
+
return { ...fragment, contentHash: fragmentHash(fragment) };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function requireMessageDictionary(table: Table): {
|
|
112
|
+
readonly message: Column<unknown>;
|
|
113
|
+
readonly dictionary: Column<unknown>;
|
|
114
|
+
readonly keys: Uint8Array | Uint16Array | Uint32Array;
|
|
115
|
+
} {
|
|
116
|
+
const message = table.getChild('message');
|
|
117
|
+
if (!message) throw new Error('Arrow table did not contain message column');
|
|
118
|
+
const batch = message.data[0];
|
|
119
|
+
if (!batch || !('dictionary' in batch) || !(batch.dictionary instanceof Column)) {
|
|
120
|
+
throw new Error('Arrow message column was not dictionary encoded');
|
|
121
|
+
}
|
|
122
|
+
if (
|
|
123
|
+
!(batch.values instanceof Uint8Array || batch.values instanceof Uint16Array || batch.values instanceof Uint32Array)
|
|
124
|
+
) {
|
|
125
|
+
throw new Error('Arrow message dictionary did not use unsigned integer keys');
|
|
126
|
+
}
|
|
127
|
+
return { dictionary: batch.dictionary, keys: batch.values, message };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const schema = defineLogSchema({ marker: S.category() });
|
|
131
|
+
const opContext = defineOpContext({ logSchema: schema });
|
|
132
|
+
|
|
133
|
+
interface DenseTemplateLogger {
|
|
134
|
+
_infoTemplate(vocabularyIndex: number): unknown;
|
|
135
|
+
_debugTemplate(vocabularyIndex: number): unknown;
|
|
136
|
+
_warnTemplate(vocabularyIndex: number): unknown;
|
|
137
|
+
_errorTemplate(vocabularyIndex: number): unknown;
|
|
138
|
+
_traceTemplate(vocabularyIndex: number): unknown;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function isDenseTemplateLogger(value: unknown): value is DenseTemplateLogger {
|
|
142
|
+
return (
|
|
143
|
+
typeof value === 'object' &&
|
|
144
|
+
value !== null &&
|
|
145
|
+
typeof Reflect.get(value, '_infoTemplate') === 'function' &&
|
|
146
|
+
typeof Reflect.get(value, '_debugTemplate') === 'function' &&
|
|
147
|
+
typeof Reflect.get(value, '_warnTemplate') === 'function' &&
|
|
148
|
+
typeof Reflect.get(value, '_errorTemplate') === 'function' &&
|
|
149
|
+
typeof Reflect.get(value, '_traceTemplate') === 'function'
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function requireDenseTemplateLogger(context: object): DenseTemplateLogger {
|
|
154
|
+
const logger = Reflect.get(context, '_spanLogger');
|
|
155
|
+
if (!isDenseTemplateLogger(logger)) throw new Error('Expected SpanContext to own a dense-template logger');
|
|
156
|
+
return logger;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
describe('runtime vocabulary dense decoding', () => {
|
|
160
|
+
it('imports Arrow vocabulary support without registering static records and exposes the empty key-zero prefix', () => {
|
|
161
|
+
const probe = Bun.spawnSync({
|
|
162
|
+
cmd: [
|
|
163
|
+
process.execPath,
|
|
164
|
+
fileURLToPath(new URL('./fixtures/empty-vocabulary-runtime.fixture.ts', import.meta.url)),
|
|
165
|
+
],
|
|
166
|
+
stdout: 'pipe',
|
|
167
|
+
stderr: 'pipe',
|
|
168
|
+
});
|
|
169
|
+
if (probe.exitCode !== 0) throw new Error(new TextDecoder().decode(probe.stderr));
|
|
170
|
+
|
|
171
|
+
expect(JSON.parse(new TextDecoder().decode(probe.stdout))).toEqual({
|
|
172
|
+
generation: 0,
|
|
173
|
+
ids: [],
|
|
174
|
+
prefixLength: 1,
|
|
175
|
+
prefixValues: [''],
|
|
176
|
+
emptyDenseIndex: 0,
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('uses the returned local binding before the first-seen dynamic suffix', async () => {
|
|
181
|
+
const staticText = 'local dense prefix literal';
|
|
182
|
+
const binding = registerVocabularyFragment(makeFragment([staticText]));
|
|
183
|
+
const op = opContext.defineOp('local-binding-static-prefix', (ctx) => {
|
|
184
|
+
const logger = requireDenseTemplateLogger(ctx);
|
|
185
|
+
logger._infoTemplate(binding[0]);
|
|
186
|
+
logger._infoTemplate(binding[0]);
|
|
187
|
+
ctx.log.info('dynamic-b');
|
|
188
|
+
ctx.log.info('dynamic-a');
|
|
189
|
+
ctx.log.info('dynamic-b');
|
|
190
|
+
return ctx.ok(null);
|
|
191
|
+
});
|
|
192
|
+
const tracer = new TestTracer(opContext, createTestTracerOptions());
|
|
193
|
+
await tracer.trace('local-binding-static-prefix', op);
|
|
194
|
+
|
|
195
|
+
const buffer = tracer.rootBuffers[0];
|
|
196
|
+
const lease = convertSpanTreeToLeasedArrowTable(buffer);
|
|
197
|
+
const table = lease.table;
|
|
198
|
+
const { dictionary, keys, message } = requireMessageDictionary(table);
|
|
199
|
+
const prefix = getVocabularyDictionaryPrefix(buffer._vocabularyGeneration);
|
|
200
|
+
const prefixValues = Array.from(prefix.column);
|
|
201
|
+
expect(Array.from(dictionary)).toEqual([...prefixValues, 'local-binding-static-prefix', 'dynamic-b', 'dynamic-a']);
|
|
202
|
+
const suffixOffset = prefix.length;
|
|
203
|
+
expect(Array.from(keys)).toEqual([
|
|
204
|
+
suffixOffset,
|
|
205
|
+
0,
|
|
206
|
+
binding[0],
|
|
207
|
+
binding[0],
|
|
208
|
+
suffixOffset + 1,
|
|
209
|
+
suffixOffset + 2,
|
|
210
|
+
suffixOffset + 1,
|
|
211
|
+
]);
|
|
212
|
+
expect(Array.from({ length: message.length }, (_, row) => message.get(row))).toEqual([
|
|
213
|
+
'local-binding-static-prefix',
|
|
214
|
+
null,
|
|
215
|
+
staticText,
|
|
216
|
+
staticText,
|
|
217
|
+
'dynamic-b',
|
|
218
|
+
'dynamic-a',
|
|
219
|
+
'dynamic-b',
|
|
220
|
+
]);
|
|
221
|
+
expect(dictionary.data).toHaveLength(2);
|
|
222
|
+
expect(dictionary.data[0]).toBe(getVocabularyDictionaryPrefix(buffer._vocabularyGeneration).column.data[0]);
|
|
223
|
+
tracer.bufferStrategy.releaseBuffer(buffer);
|
|
224
|
+
expect(message.get(4)).toBe('dynamic-b');
|
|
225
|
+
lease.release();
|
|
226
|
+
expect(lease.released).toBe(true);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('reuses the pinned cached dictionary object when overflow rows need no dynamic suffix', async () => {
|
|
230
|
+
const staticText = 'local overflow static literal';
|
|
231
|
+
const binding = registerVocabularyFragment(makeFragment([staticText]));
|
|
232
|
+
const op = opContext.defineOp('static-only-overflow', (ctx) => {
|
|
233
|
+
const logger = requireDenseTemplateLogger(ctx);
|
|
234
|
+
for (let index = 0; index < 40; index++) logger._infoTemplate(binding[0]);
|
|
235
|
+
return ctx.ok(null);
|
|
236
|
+
});
|
|
237
|
+
const tracer = new TestTracer(opContext, createTestTracerOptions());
|
|
238
|
+
await tracer.trace('static-only-overflow', op);
|
|
239
|
+
const overflow = tracer.rootBuffers[0]._overflow;
|
|
240
|
+
if (!overflow) throw new Error('Expected static log rows to create an overflow segment');
|
|
241
|
+
|
|
242
|
+
const lease = convertToLeasedArrowTable(overflow);
|
|
243
|
+
const table = lease.table;
|
|
244
|
+
const { dictionary, keys, message } = requireMessageDictionary(table);
|
|
245
|
+
const prefix = getVocabularyDictionaryPrefix(overflow._vocabularyGeneration);
|
|
246
|
+
expect(dictionary).toBe(prefix.column);
|
|
247
|
+
expect(Array.from(keys)).toEqual(Array.from({ length: message.length }, () => binding[0]));
|
|
248
|
+
expect(Array.from({ length: message.length }, (_, row) => message.get(row))).toEqual(
|
|
249
|
+
Array.from({ length: message.length }, () => staticText),
|
|
250
|
+
);
|
|
251
|
+
tracer.bufferStrategy.releaseBuffer(overflow);
|
|
252
|
+
expect(dictionary.get(binding[0])).toBe(staticText);
|
|
253
|
+
lease.release();
|
|
254
|
+
expect(lease.released).toBe(true);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('keeps registered dense bindings semantic through the default current raw lane', async () => {
|
|
258
|
+
const messages = [
|
|
259
|
+
'dense info literal',
|
|
260
|
+
'dense debug literal',
|
|
261
|
+
'dense warn literal',
|
|
262
|
+
'dense error literal',
|
|
263
|
+
'dense trace literal',
|
|
264
|
+
];
|
|
265
|
+
const binding = registerVocabularyFragment(makeFragment(messages));
|
|
266
|
+
const op = opContext.defineOp('dense-levels', (ctx) => {
|
|
267
|
+
const logger = requireDenseTemplateLogger(ctx);
|
|
268
|
+
logger._infoTemplate(binding[0]);
|
|
269
|
+
logger._debugTemplate(binding[1]);
|
|
270
|
+
logger._warnTemplate(binding[2]);
|
|
271
|
+
logger._errorTemplate(binding[3]);
|
|
272
|
+
logger._traceTemplate(binding[4]);
|
|
273
|
+
ctx.log.info('dynamic message');
|
|
274
|
+
return ctx.ok(null);
|
|
275
|
+
});
|
|
276
|
+
const tracer = new TestTracer(opContext, createTestTracerOptions());
|
|
277
|
+
await tracer.trace('dense-levels', op);
|
|
278
|
+
const buffer = tracer.rootBuffers[0];
|
|
279
|
+
const localIds = buffer._messageIds;
|
|
280
|
+
const rawMessages = buffer.message_values;
|
|
281
|
+
if (!localIds || !rawMessages) throw new Error('Expected current local-ID and raw lanes');
|
|
282
|
+
expect(buffer._messagePhysicalLayout).toBe('current');
|
|
283
|
+
expect(buffer._opMetadata._physicalLayoutPlan?.localMessageDictionary).toEqual([]);
|
|
284
|
+
expect('_logHeaders' in buffer).toBe(false);
|
|
285
|
+
expect('message_nulls' in buffer).toBe(false);
|
|
286
|
+
expect(Array.from(localIds.subarray(2, 8))).toEqual([0, 0, 0, 0, 0, 0]);
|
|
287
|
+
expect(rawMessages.slice(2, 8)).toEqual([...messages, 'dynamic message']);
|
|
288
|
+
expect(Array.from({ length: 6 }, (_, index) => resolveMessage(buffer, index + 2))).toEqual([
|
|
289
|
+
...messages,
|
|
290
|
+
'dynamic message',
|
|
291
|
+
]);
|
|
292
|
+
|
|
293
|
+
const table = convertToArrowTable(buffer);
|
|
294
|
+
const messageColumn = table.getChild('message');
|
|
295
|
+
if (!messageColumn) throw new Error('Arrow table did not contain message column');
|
|
296
|
+
expect(Array.from({ length: 6 }, (_, index) => messageColumn.get(index + 2))).toEqual([
|
|
297
|
+
...messages,
|
|
298
|
+
'dynamic message',
|
|
299
|
+
]);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('keeps overflow rows pinned to their original vocabulary generation after later registration', async () => {
|
|
303
|
+
const firstBinding = registerVocabularyFragment(makeFragment(['pinned generation literal']));
|
|
304
|
+
const op = opContext.defineOp('dense-overflow-generation', (ctx) => {
|
|
305
|
+
const logger = requireDenseTemplateLogger(ctx);
|
|
306
|
+
for (let index = 0; index < 20; index++) logger._infoTemplate(firstBinding[0]);
|
|
307
|
+
return ctx.ok(null);
|
|
308
|
+
});
|
|
309
|
+
const tracer = new TestTracer(opContext, createTestTracerOptions());
|
|
310
|
+
await tracer.trace('dense-overflow-generation', op);
|
|
311
|
+
const buffer = tracer.rootBuffers[0];
|
|
312
|
+
|
|
313
|
+
registerVocabularyFragment(makeFragment(['registered after buffer creation']));
|
|
314
|
+
|
|
315
|
+
const lease = convertSpanTreeToLeasedArrowTable(buffer);
|
|
316
|
+
const table = lease.table;
|
|
317
|
+
const messageColumn = table.getChild('message');
|
|
318
|
+
if (!messageColumn) throw new Error('Arrow table did not contain message column');
|
|
319
|
+
expect(Array.from({ length: 20 }, (_, index) => messageColumn.get(index + 2))).toEqual(
|
|
320
|
+
Array.from({ length: 20 }, () => 'pinned generation literal'),
|
|
321
|
+
);
|
|
322
|
+
const { dictionary } = requireMessageDictionary(table);
|
|
323
|
+
expect(dictionary.data[0]).toBe(getVocabularyDictionaryPrefix(buffer._vocabularyGeneration).column.data[0]);
|
|
324
|
+
expect(Array.from(dictionary)).toContain('pinned generation literal');
|
|
325
|
+
expect(Array.from(dictionary)).not.toContain('registered after buffer creation');
|
|
326
|
+
expect(lease.released).toBe(false);
|
|
327
|
+
tracer.bufferStrategy.releaseBuffer(buffer);
|
|
328
|
+
expect(() => buffer._traceRoot._topology.assertLive(buffer)).toThrow('stale');
|
|
329
|
+
expect(messageColumn.get(2)).toBe('pinned generation literal');
|
|
330
|
+
lease[Symbol.dispose]();
|
|
331
|
+
expect(lease.released).toBe(true);
|
|
332
|
+
expect(() => buffer._traceRoot._topology.assertLive(buffer)).toThrow('stale');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('rejects a packed dense index outside the buffer generation', async () => {
|
|
336
|
+
let invalidDenseIndex = 0;
|
|
337
|
+
const op = opContext.defineOp(
|
|
338
|
+
'invalid-dense-index',
|
|
339
|
+
(ctx) => {
|
|
340
|
+
const logger = requireDenseTemplateLogger(ctx);
|
|
341
|
+
invalidDenseIndex = ctx.buffer._vocabularyGeneration.ids.length;
|
|
342
|
+
logger._infoTemplate(invalidDenseIndex);
|
|
343
|
+
return ctx.ok(null);
|
|
344
|
+
},
|
|
345
|
+
undefined,
|
|
346
|
+
{
|
|
347
|
+
runtimeHint:
|
|
348
|
+
RUNTIME_HINT_ANALYZED_VALID |
|
|
349
|
+
RUNTIME_HINT_LOG |
|
|
350
|
+
RUNTIME_HINT_RESULT |
|
|
351
|
+
RUNTIME_HINT_MESSAGE_LAYOUT_MIXED |
|
|
352
|
+
RUNTIME_HINT_MESSAGE_PHYSICAL_PACKED |
|
|
353
|
+
3,
|
|
354
|
+
},
|
|
355
|
+
);
|
|
356
|
+
const tracer = new TestTracer(opContext, createTestTracerOptions());
|
|
357
|
+
await tracer.trace('invalid-dense-index', op);
|
|
358
|
+
const buffer = tracer.rootBuffers[0];
|
|
359
|
+
|
|
360
|
+
expect(() => resolveMessage(buffer, 2)).toThrow(
|
|
361
|
+
`Invalid vocabulary dense index ${invalidDenseIndex} for generation ${buffer._vocabularyGeneration.generation}`,
|
|
362
|
+
);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('deduplicates repeated registration without a new observable generation', () => {
|
|
366
|
+
const fragment = makeFragment(['single registration owner']);
|
|
367
|
+
const firstBinding = registerVocabularyFragment(fragment);
|
|
368
|
+
const generation = getVocabularyGeneration();
|
|
369
|
+
const secondBinding = registerVocabularyFragment(fragment);
|
|
370
|
+
|
|
371
|
+
expect(secondBinding).toBe(firstBinding);
|
|
372
|
+
expect(getVocabularyGeneration()).toBe(generation);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('leaves child span lifecycle hooks and Promise scheduling unchanged', async () => {
|
|
376
|
+
const lifecycleContext = defineOpContext({ logSchema: schema });
|
|
377
|
+
type LifecycleSchema = (typeof lifecycleContext)['logBinding']['logSchema'];
|
|
378
|
+
class LifecycleTracer extends TestTracer<typeof lifecycleContext> {
|
|
379
|
+
starts = 0;
|
|
380
|
+
ends = 0;
|
|
381
|
+
|
|
382
|
+
override onSpanStart(_buffer: SpanBuffer<LifecycleSchema>): void {
|
|
383
|
+
this.starts++;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
override onSpanEnd(_buffer: SpanBuffer<LifecycleSchema>): void {
|
|
387
|
+
this.ends++;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const child = lifecycleContext.defineOp('child', (ctx) => ctx.ok('child'), undefined, { runtimeHint: 0 });
|
|
392
|
+
const parent = lifecycleContext.defineOp('parent', async (ctx) => {
|
|
393
|
+
const pending = ctx.span('child-call', child);
|
|
394
|
+
expect(pending).toBeInstanceOf(Promise);
|
|
395
|
+
await pending;
|
|
396
|
+
return ctx.ok('parent');
|
|
397
|
+
});
|
|
398
|
+
const tracer = new LifecycleTracer(lifecycleContext, createTestTracerOptions());
|
|
399
|
+
|
|
400
|
+
await tracer.trace('root', parent);
|
|
401
|
+
expect(tracer.starts).toBe(1);
|
|
402
|
+
expect(tracer.ends).toBe(1);
|
|
403
|
+
expect(tracer.rootBuffers).toHaveLength(1);
|
|
404
|
+
});
|
|
405
|
+
});
|