@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
package/src/lib/spanBuffer.ts
CHANGED
|
@@ -25,15 +25,23 @@
|
|
|
25
25
|
* @module spanBuffer
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
activeMaterializerMode,
|
|
30
|
+
type ColumnBufferExtension,
|
|
31
|
+
DEFAULT_BUFFER_CAPACITY,
|
|
32
|
+
getColumnBufferClass,
|
|
33
|
+
type SchemaWithMetadata,
|
|
34
|
+
} from '@smoothbricks/arrow-builder';
|
|
29
35
|
import { checkCapacityTuning } from './capacityTuning.js';
|
|
30
36
|
import type { OpMetadata } from './opContext/opTypes.js';
|
|
31
|
-
import type {
|
|
32
|
-
import {
|
|
37
|
+
import type { EagerColumnDescriptor } from './physicalLayoutPlan.js';
|
|
38
|
+
import type { MessageLayoutFamily, MessagePhysicalLayout } from './runtimeHint.js';
|
|
39
|
+
import { LogSchema } from './schema/LogSchema.js';
|
|
33
40
|
import type { SpanBufferStats } from './spanBufferStats.js';
|
|
34
|
-
import {
|
|
41
|
+
import { copyThreadIdTo, getThreadId } from './threadId.js';
|
|
35
42
|
import type { ITraceRoot } from './traceRoot.js';
|
|
36
43
|
import type { AnySpanBuffer, SpanBuffer } from './types.js';
|
|
44
|
+
import { getVocabularyGeneration, type VocabularyGeneration } from './vocabularyRegistry.js';
|
|
37
45
|
|
|
38
46
|
// Re-export ITraceRoot for external consumers (and to satisfy linter - it's used in generated code)
|
|
39
47
|
export type { ITraceRoot };
|
|
@@ -44,8 +52,6 @@ export type { ITraceRoot };
|
|
|
44
52
|
*/
|
|
45
53
|
export const EMPTY_SCOPE: Readonly<Record<string, unknown>> = Object.freeze({});
|
|
46
54
|
|
|
47
|
-
const traceIdDecoder = new TextDecoder();
|
|
48
|
-
|
|
49
55
|
// ============================================================================
|
|
50
56
|
// Thread-local state (generated once per process/worker)
|
|
51
57
|
// These are used by the generated class code via the constructorPreamble
|
|
@@ -132,11 +138,15 @@ export interface SpanBufferConstructor<T extends LogSchema = LogSchema> {
|
|
|
132
138
|
callsiteMetadata: OpMetadata | undefined,
|
|
133
139
|
opMetadata: OpMetadata | undefined,
|
|
134
140
|
traceRoot: ITraceRoot,
|
|
141
|
+
vocabularyGeneration: VocabularyGeneration,
|
|
135
142
|
): SpanBuffer<T>;
|
|
136
143
|
|
|
137
144
|
// Static properties added after class generation
|
|
138
145
|
readonly schema: T;
|
|
139
146
|
readonly stats: SpanBufferStats;
|
|
147
|
+
readonly messageLayoutFamily: MessageLayoutFamily;
|
|
148
|
+
readonly messagePhysicalLayout: MessagePhysicalLayout;
|
|
149
|
+
readonly eagerColumns: EagerColumnDescriptor;
|
|
140
150
|
}
|
|
141
151
|
//#endregion smoo/lmao!n/spanbuffer-layout.class-signature
|
|
142
152
|
|
|
@@ -148,6 +158,7 @@ type GeneratedSpanBufferClass<T extends LogSchema> = new (
|
|
|
148
158
|
callsiteMetadata: OpMetadata | undefined,
|
|
149
159
|
opMetadata: OpMetadata | undefined,
|
|
150
160
|
traceRoot: ITraceRoot,
|
|
161
|
+
vocabularyGeneration: VocabularyGeneration,
|
|
151
162
|
) => SpanBuffer<T>;
|
|
152
163
|
|
|
153
164
|
function isGeneratedSpanBufferClass<T extends LogSchema>(
|
|
@@ -160,6 +171,8 @@ function isGeneratedSpanBufferClass<T extends LogSchema>(
|
|
|
160
171
|
|
|
161
172
|
return (
|
|
162
173
|
typeof Reflect.get(prototype, 'getOrCreateOverflow') === 'function' &&
|
|
174
|
+
typeof Reflect.get(prototype, '_sealStats') === 'function' &&
|
|
175
|
+
typeof Reflect.get(prototype, '_sealStatsChain') === 'function' &&
|
|
163
176
|
typeof Reflect.get(prototype, 'isParentOf') === 'function' &&
|
|
164
177
|
typeof Reflect.get(prototype, 'isChildOf') === 'function'
|
|
165
178
|
);
|
|
@@ -186,23 +199,438 @@ function getSpanBufferConstructorForBuffer<T extends LogSchema>(buffer: SpanBuff
|
|
|
186
199
|
|
|
187
200
|
function createSpanBufferConstructor<T extends LogSchema>(
|
|
188
201
|
schema: T,
|
|
202
|
+
messageLayoutFamily: MessageLayoutFamily,
|
|
203
|
+
messagePhysicalLayout: MessagePhysicalLayout,
|
|
189
204
|
generatedClass: GeneratedSpanBufferClass<T>,
|
|
205
|
+
eagerColumns: EagerColumnDescriptor,
|
|
190
206
|
): SpanBufferConstructor<T> {
|
|
191
|
-
|
|
192
|
-
schema,
|
|
207
|
+
Object.defineProperties(generatedClass, {
|
|
208
|
+
schema: { value: schema, enumerable: true },
|
|
209
|
+
messageLayoutFamily: { value: messageLayoutFamily, enumerable: true },
|
|
210
|
+
messagePhysicalLayout: { value: messagePhysicalLayout, enumerable: true },
|
|
211
|
+
eagerColumns: { value: eagerColumns, enumerable: true },
|
|
193
212
|
stats: {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
213
|
+
value: {
|
|
214
|
+
capacity: DEFAULT_BUFFER_CAPACITY,
|
|
215
|
+
totalWrites: 0,
|
|
216
|
+
spansCreated: 0,
|
|
217
|
+
} satisfies SpanBufferStats,
|
|
218
|
+
enumerable: true,
|
|
219
|
+
},
|
|
198
220
|
});
|
|
221
|
+
|
|
222
|
+
if (!isSpanBufferConstructorForSchema(generatedClass, schema)) {
|
|
223
|
+
throw new TypeError('Generated column buffer constructor initialization failed');
|
|
224
|
+
}
|
|
225
|
+
return generatedClass;
|
|
199
226
|
}
|
|
200
227
|
|
|
201
228
|
/**
|
|
202
229
|
* Cache for generated SpanBuffer classes per schema.
|
|
203
230
|
* Key is the schema object reference (WeakMap for GC).
|
|
204
231
|
*/
|
|
205
|
-
const spanBufferClassCache = new WeakMap<LogSchema,
|
|
232
|
+
const spanBufferClassCache = new WeakMap<LogSchema, Map<string, object>>();
|
|
233
|
+
const messageStorageSchemas = new WeakMap<LogSchema, Map<string, LogSchema>>();
|
|
234
|
+
const EMPTY_EAGER_COLUMNS: EagerColumnDescriptor = Object.freeze({
|
|
235
|
+
names: Object.freeze([]),
|
|
236
|
+
words: Object.freeze([]),
|
|
237
|
+
key: '',
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
function resolveCompiledEagerColumns(schema: LogSchema, requestedNames: readonly string[]): EagerColumnDescriptor {
|
|
241
|
+
if (requestedNames.length === 0) return EMPTY_EAGER_COLUMNS;
|
|
242
|
+
const requested = new Set(requestedNames);
|
|
243
|
+
const names: string[] = [];
|
|
244
|
+
const words = new Array<number>(Math.ceil(schema._columnNames.length / 32)).fill(0);
|
|
245
|
+
for (let columnIndex = 0; columnIndex < schema._columnNames.length; columnIndex++) {
|
|
246
|
+
const name = schema._columnNames[columnIndex];
|
|
247
|
+
if (!requested.delete(name)) continue;
|
|
248
|
+
names.push(name);
|
|
249
|
+
const wordIndex = columnIndex >>> 5;
|
|
250
|
+
words[wordIndex] = (words[wordIndex] | (1 << (columnIndex & 31))) >>> 0;
|
|
251
|
+
}
|
|
252
|
+
if (requested.size !== 0) {
|
|
253
|
+
throw new TypeError(
|
|
254
|
+
`Unknown compiled eager column${requested.size === 1 ? '' : 's'}: ${[...requested].join(', ')}`,
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
while (words.length !== 0 && words[words.length - 1] === 0) words.pop();
|
|
258
|
+
const frozenWords = Object.freeze(words);
|
|
259
|
+
return Object.freeze({
|
|
260
|
+
names: Object.freeze(names),
|
|
261
|
+
words: frozenWords,
|
|
262
|
+
key: frozenWords.map((word) => word.toString(16).padStart(8, '0')).join(''),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function getStorageSchema(
|
|
267
|
+
schema: LogSchema,
|
|
268
|
+
messageLayoutFamily: MessageLayoutFamily,
|
|
269
|
+
messagePhysicalLayout: MessagePhysicalLayout,
|
|
270
|
+
): LogSchema {
|
|
271
|
+
let byLayout = messageStorageSchemas.get(schema);
|
|
272
|
+
const key = `${messageLayoutFamily}:${messagePhysicalLayout}`;
|
|
273
|
+
let storageSchema = byLayout?.get(key);
|
|
274
|
+
if (storageSchema === undefined) {
|
|
275
|
+
const fields: Record<string, SchemaWithMetadata> = {};
|
|
276
|
+
for (const [name, field] of schema._columns) {
|
|
277
|
+
if (name !== 'message') fields[name] = field;
|
|
278
|
+
}
|
|
279
|
+
storageSchema = new LogSchema(fields);
|
|
280
|
+
byLayout ??= new Map();
|
|
281
|
+
byLayout.set(key, storageSchema);
|
|
282
|
+
messageStorageSchemas.set(schema, byLayout);
|
|
283
|
+
}
|
|
284
|
+
return storageSchema;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Canonicalize a ttsc-emitted SpanBuffer class into the same schema/layout cache
|
|
289
|
+
* used by the dynamic fallback. The factory is lazy so an already materialized
|
|
290
|
+
* class wins without allocating a duplicate constructor.
|
|
291
|
+
*/
|
|
292
|
+
export function materializeCompiledSpanBufferClass<T extends LogSchema>(
|
|
293
|
+
schema: T,
|
|
294
|
+
messageLayoutFamily: MessageLayoutFamily,
|
|
295
|
+
messagePhysicalLayout: MessagePhysicalLayout,
|
|
296
|
+
eagerColumnNames: readonly string[],
|
|
297
|
+
factory: () => new (...args: never[]) => unknown,
|
|
298
|
+
): SpanBufferConstructor<T> {
|
|
299
|
+
const eagerColumns = resolveCompiledEagerColumns(schema, eagerColumnNames);
|
|
300
|
+
// Mode-prefixed like arrow-builder's class caches: the materializer mode is fixed for a process,
|
|
301
|
+
// but the parity suite flips it via override and must never see the other mode's class.
|
|
302
|
+
const cacheKey = `${activeMaterializerMode()}:${messageLayoutFamily}:${messagePhysicalLayout}:${eagerColumns.key}`;
|
|
303
|
+
let familyClasses = spanBufferClassCache.get(schema);
|
|
304
|
+
const cached = familyClasses?.get(cacheKey);
|
|
305
|
+
if (
|
|
306
|
+
isSpanBufferConstructorForSchema(cached, schema) &&
|
|
307
|
+
cached.messageLayoutFamily === messageLayoutFamily &&
|
|
308
|
+
cached.messagePhysicalLayout === messagePhysicalLayout
|
|
309
|
+
) {
|
|
310
|
+
return cached;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const compiledClass = factory();
|
|
314
|
+
if (!isGeneratedSpanBufferClass<T>(compiledClass)) {
|
|
315
|
+
throw new TypeError('Compiled SpanBuffer class is missing the required buffer contract');
|
|
316
|
+
}
|
|
317
|
+
const SpanBufferClass = createSpanBufferConstructor(
|
|
318
|
+
schema,
|
|
319
|
+
messageLayoutFamily,
|
|
320
|
+
messagePhysicalLayout,
|
|
321
|
+
compiledClass,
|
|
322
|
+
eagerColumns,
|
|
323
|
+
);
|
|
324
|
+
familyClasses ??= new Map();
|
|
325
|
+
familyClasses.set(cacheKey, SpanBufferClass);
|
|
326
|
+
spanBufferClassCache.set(schema, familyClasses);
|
|
327
|
+
return SpanBufferClass;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ============================================================================
|
|
331
|
+
// No-eval (closure-composed) extension counterparts
|
|
332
|
+
// ============================================================================
|
|
333
|
+
// Production workerd forbids code generation from strings, so arrow-builder
|
|
334
|
+
// materializes the buffer class from closures there (see arrow-builder's
|
|
335
|
+
// closureMaterializers). The two factories below are the EXACT no-eval
|
|
336
|
+
// re-expressions of the code-string constructorPreamble/methods passed in the
|
|
337
|
+
// extension inside getSpanBufferClass — any change to one side MUST be
|
|
338
|
+
// mirrored on the other (spanbuffer-materializer-parity.test.ts compares the
|
|
339
|
+
// resulting buffers byte for byte).
|
|
340
|
+
|
|
341
|
+
/** Prototype/instance view used by the closure-composed members. */
|
|
342
|
+
type ClosureSelf = AnySpanBuffer & Record<string, unknown>;
|
|
343
|
+
|
|
344
|
+
// Thread-local span counter contract shared with the generated constructorPreamble
|
|
345
|
+
// (`globalThis.globalSpanCounter`), see threadId.ts docs.
|
|
346
|
+
declare global {
|
|
347
|
+
var globalSpanCounter: number | undefined;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function isSpanBufferConstructorValue(value: unknown): value is SpanBufferConstructor {
|
|
351
|
+
return typeof value === 'function';
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function spanBufferStatics(self: AnySpanBuffer): SpanBufferConstructor {
|
|
355
|
+
const ctor = self.constructor;
|
|
356
|
+
if (!isSpanBufferConstructorValue(ctor)) throw new TypeError('SpanBuffer constructor is not initialized');
|
|
357
|
+
return ctor;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** Constructor arguments arrive untyped through the materializer; every real buffer/traceRoot is an object. */
|
|
361
|
+
function isSpanBufferValue(value: unknown): value is AnySpanBuffer {
|
|
362
|
+
return typeof value === 'object' && value !== null;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function isTraceRootValue(value: unknown): value is ITraceRoot {
|
|
366
|
+
return typeof value === 'object' && value !== null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function requireParent(parent: AnySpanBuffer | undefined): AnySpanBuffer {
|
|
370
|
+
if (parent === undefined) throw new TypeError('Chained/child SpanBuffer construction requires a parent buffer');
|
|
371
|
+
return parent;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** Every runtime SpanBuffer instance satisfies the typed SpanBuffer contract (dynamic column lanes included). */
|
|
375
|
+
function isTypedSpanBuffer(value: AnySpanBuffer): value is SpanBuffer<LogSchema> {
|
|
376
|
+
return typeof value === 'object' && value !== null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** Mirrors the generated `_sealStats` body (shared with getOrCreateOverflow). */
|
|
380
|
+
function sealStatsFor(self: AnySpanBuffer): void {
|
|
381
|
+
if (self._statsSealed) return;
|
|
382
|
+
const completedRows = self._writeIndex - self._statsReservedRows;
|
|
383
|
+
if (completedRows > 0) spanBufferStatics(self).stats.totalWrites += completedRows;
|
|
384
|
+
self._statsSealed = true;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* No-eval counterpart of the extension `constructorPreamble` (and its
|
|
389
|
+
* `constructorParams` signature): identical buffer-type branches (root /
|
|
390
|
+
* child / chained), identical physical system layout math, identical
|
|
391
|
+
* property-assignment order (V8 in-object slots).
|
|
392
|
+
*/
|
|
393
|
+
function createSpanBufferClosureInit(
|
|
394
|
+
messageLayoutFamily: MessageLayoutFamily,
|
|
395
|
+
messagePhysicalLayout: MessagePhysicalLayout,
|
|
396
|
+
): NonNullable<ColumnBufferExtension['closureInit']> {
|
|
397
|
+
return (self, requestedCapacity, ctorArgs) => {
|
|
398
|
+
// ctorArgs mirror constructorParams: stats, parent, isChained, callsiteMetadata, opMetadata, traceRoot, vocabularyGeneration
|
|
399
|
+
const parent = isSpanBufferValue(ctorArgs[1]) ? ctorArgs[1] : undefined;
|
|
400
|
+
const isChained = Boolean(ctorArgs[2]);
|
|
401
|
+
const callsiteMetadata = ctorArgs[3];
|
|
402
|
+
const opMetadata = ctorArgs[4];
|
|
403
|
+
const traceRootArg = ctorArgs[5];
|
|
404
|
+
if (!isTraceRootValue(traceRootArg)) throw new TypeError('SpanBuffer construction requires a traceRoot');
|
|
405
|
+
const traceRoot = traceRootArg;
|
|
406
|
+
const vocabularyGeneration = ctorArgs[6];
|
|
407
|
+
|
|
408
|
+
// Thread-local span counter (per-process/worker, see threadId.ts docs)
|
|
409
|
+
globalThis.globalSpanCounter = (globalThis.globalSpanCounter ?? 0) + 1;
|
|
410
|
+
const spanId = globalThis.globalSpanCounter;
|
|
411
|
+
const threadId = isChained ? requireParent(parent).thread_id : getThreadId();
|
|
412
|
+
|
|
413
|
+
// Calculate exact physical system storage (same math as the preamble variants).
|
|
414
|
+
let systemSize: number;
|
|
415
|
+
let rowHeaderOffset = 0;
|
|
416
|
+
let messageIdOffset = 0;
|
|
417
|
+
let logHeaderOffset = 0;
|
|
418
|
+
if (messagePhysicalLayout === 'packed') {
|
|
419
|
+
rowHeaderOffset = requestedCapacity * 8;
|
|
420
|
+
systemSize = (requestedCapacity * 12 + 7) & ~7;
|
|
421
|
+
} else if (messageLayoutFamily === 'dynamic-only') {
|
|
422
|
+
systemSize = (requestedCapacity * 9 + 7) & ~7;
|
|
423
|
+
} else if (messagePhysicalLayout === 'current') {
|
|
424
|
+
messageIdOffset = (requestedCapacity * 9 + 1) & ~1;
|
|
425
|
+
systemSize = (messageIdOffset + requestedCapacity * 2 + 7) & ~7;
|
|
426
|
+
} else {
|
|
427
|
+
logHeaderOffset = (requestedCapacity * 9 + 3) & ~3;
|
|
428
|
+
systemSize = (logHeaderOffset + requestedCapacity * 4 + 7) & ~7;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// CHAINED: shares parent._identity; CHILD: identity without traceId; ROOT: identity with traceId bytes.
|
|
432
|
+
let systemBuffer: ArrayBuffer;
|
|
433
|
+
let identityView: Uint8Array;
|
|
434
|
+
if (isChained) {
|
|
435
|
+
systemBuffer = new ArrayBuffer(systemSize);
|
|
436
|
+
identityView = requireParent(parent)._identity;
|
|
437
|
+
} else if (parent) {
|
|
438
|
+
const identitySize = 12;
|
|
439
|
+
systemBuffer = new ArrayBuffer(systemSize + identitySize);
|
|
440
|
+
identityView = new Uint8Array(systemBuffer, systemSize, identitySize);
|
|
441
|
+
copyThreadIdTo(identityView, 0);
|
|
442
|
+
identityView[8] = spanId;
|
|
443
|
+
identityView[9] = spanId >>> 8;
|
|
444
|
+
identityView[10] = spanId >>> 16;
|
|
445
|
+
identityView[11] = spanId >>> 24;
|
|
446
|
+
} else {
|
|
447
|
+
const traceIdBytes = traceRoot._traceIdBytes;
|
|
448
|
+
const identitySize = 13 + traceIdBytes.length;
|
|
449
|
+
systemBuffer = new ArrayBuffer(systemSize + identitySize);
|
|
450
|
+
identityView = new Uint8Array(systemBuffer, systemSize, identitySize);
|
|
451
|
+
copyThreadIdTo(identityView, 0);
|
|
452
|
+
identityView[8] = spanId;
|
|
453
|
+
identityView[9] = spanId >>> 8;
|
|
454
|
+
identityView[10] = spanId >>> 16;
|
|
455
|
+
identityView[11] = spanId >>> 24;
|
|
456
|
+
identityView[12] = traceIdBytes.length;
|
|
457
|
+
identityView.set(traceIdBytes, 13);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Assign properties in the optimal V8 in-object slot order (same as the preamble).
|
|
461
|
+
self._writeIndex = 0;
|
|
462
|
+
self._capacity = requestedCapacity;
|
|
463
|
+
self._overflow = undefined;
|
|
464
|
+
self.timestamp = new BigInt64Array(systemBuffer, 0, requestedCapacity);
|
|
465
|
+
if (messagePhysicalLayout === 'packed') {
|
|
466
|
+
self._rowHeaders = new Uint32Array(systemBuffer, rowHeaderOffset, requestedCapacity);
|
|
467
|
+
} else {
|
|
468
|
+
self.entry_type = new Uint8Array(systemBuffer, requestedCapacity * 8, requestedCapacity);
|
|
469
|
+
if (messageLayoutFamily !== 'dynamic-only') {
|
|
470
|
+
if (messagePhysicalLayout === 'current') {
|
|
471
|
+
self._messageIds = new Uint16Array(systemBuffer, messageIdOffset, requestedCapacity);
|
|
472
|
+
} else {
|
|
473
|
+
self._logHeaders = new Uint32Array(systemBuffer, logHeaderOffset, requestedCapacity);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
self._vocabularyGeneration = vocabularyGeneration;
|
|
478
|
+
if (messageLayoutFamily === 'static-only') {
|
|
479
|
+
self._spanName = undefined;
|
|
480
|
+
self._terminalMessage = undefined;
|
|
481
|
+
} else if (messageLayoutFamily === 'dynamic-only') {
|
|
482
|
+
self._spanName = undefined;
|
|
483
|
+
}
|
|
484
|
+
self._nodeIndex = 4294967295;
|
|
485
|
+
self._topologyGeneration = 0;
|
|
486
|
+
self._parent = isChained ? requireParent(parent)._parent : parent;
|
|
487
|
+
self._traceRoot = traceRoot;
|
|
488
|
+
self._scopeValues = parent ? parent._scopeValues : EMPTY_SCOPE;
|
|
489
|
+
self._threadId = threadId;
|
|
490
|
+
self._identity = identityView;
|
|
491
|
+
self._system = systemBuffer;
|
|
492
|
+
self._callsiteMetadata = callsiteMetadata;
|
|
493
|
+
self._opMetadata = opMetadata;
|
|
494
|
+
self._statsSealed = false;
|
|
495
|
+
self._statsReservedRows = isChained ? 0 : 2;
|
|
496
|
+
if (messageLayoutFamily !== 'static-only') {
|
|
497
|
+
self.message_values = new Array(requestedCapacity);
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* No-eval counterpart of the extension `methods` string: same members, same
|
|
504
|
+
* kinds (getter vs method), installed after the generated per-column members
|
|
505
|
+
* so same-named members override exactly like the compiled class body.
|
|
506
|
+
*/
|
|
507
|
+
function createSpanBufferClosureMethods(
|
|
508
|
+
messageLayoutFamily: MessageLayoutFamily,
|
|
509
|
+
): NonNullable<ColumnBufferExtension['closureMethods']> {
|
|
510
|
+
return (prototype) => {
|
|
511
|
+
const defineMethod = (name: string, value: unknown): void => {
|
|
512
|
+
Object.defineProperty(prototype, name, { value, writable: true, configurable: true, enumerable: false });
|
|
513
|
+
};
|
|
514
|
+
const defineGetter = (name: string, get: (this: ClosureSelf) => unknown): void => {
|
|
515
|
+
Object.defineProperty(prototype, name, { get, configurable: true, enumerable: false });
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
defineGetter('span_id', function () {
|
|
519
|
+
const b = this._identity;
|
|
520
|
+
return b ? (b[8] | (b[9] << 8) | (b[10] << 16) | (b[11] << 24)) >>> 0 : 0;
|
|
521
|
+
});
|
|
522
|
+
defineGetter('thread_id', function () {
|
|
523
|
+
return this._threadId;
|
|
524
|
+
});
|
|
525
|
+
defineGetter('trace_id', function () {
|
|
526
|
+
return this._traceRoot.trace_id;
|
|
527
|
+
});
|
|
528
|
+
defineGetter('_spanStartTime', function () {
|
|
529
|
+
return this.timestamp[0];
|
|
530
|
+
});
|
|
531
|
+
defineGetter('_lastLoggedTime', function () {
|
|
532
|
+
const chain: AnySpanBuffer[] = [];
|
|
533
|
+
let current: AnySpanBuffer | undefined = this;
|
|
534
|
+
while (current) {
|
|
535
|
+
chain.push(current);
|
|
536
|
+
current = current._overflow;
|
|
537
|
+
}
|
|
538
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
539
|
+
const buffer = chain[i];
|
|
540
|
+
for (let row = buffer._writeIndex - 1; row >= 0; row--) {
|
|
541
|
+
const ts = buffer.timestamp[row];
|
|
542
|
+
if (ts !== 0n) {
|
|
543
|
+
return ts;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return null;
|
|
548
|
+
});
|
|
549
|
+
defineGetter('_hasParent', function () {
|
|
550
|
+
return this._parent !== undefined;
|
|
551
|
+
});
|
|
552
|
+
defineGetter('parent_span_id', function () {
|
|
553
|
+
return this._parent?.span_id ?? 0;
|
|
554
|
+
});
|
|
555
|
+
defineGetter('parent_thread_id', function () {
|
|
556
|
+
return this._parent?.thread_id ?? 0n;
|
|
557
|
+
});
|
|
558
|
+
defineMethod('isParentOf', function (this: ClosureSelf, other: AnySpanBuffer) {
|
|
559
|
+
return this === other._parent;
|
|
560
|
+
});
|
|
561
|
+
defineMethod('isChildOf', function (this: ClosureSelf, other: AnySpanBuffer) {
|
|
562
|
+
return this._parent === other;
|
|
563
|
+
});
|
|
564
|
+
defineMethod('copyThreadIdTo', function (this: ClosureSelf, dest: Uint8Array, offset: number) {
|
|
565
|
+
const source = this._identity;
|
|
566
|
+
if (source) {
|
|
567
|
+
dest[offset] = source[0];
|
|
568
|
+
dest[offset + 1] = source[1];
|
|
569
|
+
dest[offset + 2] = source[2];
|
|
570
|
+
dest[offset + 3] = source[3];
|
|
571
|
+
dest[offset + 4] = source[4];
|
|
572
|
+
dest[offset + 5] = source[5];
|
|
573
|
+
dest[offset + 6] = source[6];
|
|
574
|
+
dest[offset + 7] = source[7];
|
|
575
|
+
} else {
|
|
576
|
+
dest.fill(0, offset, offset + 8);
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
defineMethod('copyParentThreadIdTo', function (this: ClosureSelf, dest: Uint8Array, offset: number) {
|
|
580
|
+
if (this._parent) this._parent.copyThreadIdTo(dest, offset);
|
|
581
|
+
else dest.fill(0, offset, offset + 8);
|
|
582
|
+
});
|
|
583
|
+
defineGetter('_logSchema', function () {
|
|
584
|
+
return spanBufferStatics(this).schema;
|
|
585
|
+
});
|
|
586
|
+
defineGetter('_messageLayoutFamily', function () {
|
|
587
|
+
return spanBufferStatics(this).messageLayoutFamily;
|
|
588
|
+
});
|
|
589
|
+
defineGetter('_messagePhysicalLayout', function () {
|
|
590
|
+
return spanBufferStatics(this).messagePhysicalLayout;
|
|
591
|
+
});
|
|
592
|
+
defineGetter('_columns', function () {
|
|
593
|
+
return spanBufferStatics(this).schema._columns;
|
|
594
|
+
});
|
|
595
|
+
defineGetter('_stats', function () {
|
|
596
|
+
return spanBufferStatics(this).stats;
|
|
597
|
+
});
|
|
598
|
+
defineMethod('_sealStats', function (this: ClosureSelf) {
|
|
599
|
+
sealStatsFor(this);
|
|
600
|
+
});
|
|
601
|
+
defineMethod('_sealStatsChain', function (this: ClosureSelf) {
|
|
602
|
+
let current: AnySpanBuffer | undefined = this;
|
|
603
|
+
while (current) {
|
|
604
|
+
sealStatsFor(current);
|
|
605
|
+
current = current._overflow;
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
defineMethod('getOrCreateOverflow', function (this: ClosureSelf) {
|
|
609
|
+
if (this._overflow) return this._overflow;
|
|
610
|
+
sealStatsFor(this);
|
|
611
|
+
const tracer = this._traceRoot.tracer;
|
|
612
|
+
tracer.onStatsWillResetFor(this);
|
|
613
|
+
checkCapacityTuning(spanBufferStatics(this).stats);
|
|
614
|
+
if (!isTypedSpanBuffer(this)) throw new TypeError('SpanBuffer instance is not initialized');
|
|
615
|
+
return tracer.bufferStrategy.createOverflowBuffer(this);
|
|
616
|
+
});
|
|
617
|
+
if (messageLayoutFamily === 'static-only') {
|
|
618
|
+
defineMethod('message', function (this: ClosureSelf, pos: number, val: string) {
|
|
619
|
+
if (pos === 0) this._spanName = val;
|
|
620
|
+
else if (pos === 1) this._terminalMessage = val;
|
|
621
|
+
else throw new RangeError('Static-only buffers only accept raw system messages at rows 0 and 1');
|
|
622
|
+
return this;
|
|
623
|
+
});
|
|
624
|
+
} else {
|
|
625
|
+
defineMethod('message', function (this: ClosureSelf, pos: number, val: string) {
|
|
626
|
+
const lane: unknown = this.message_values;
|
|
627
|
+
if (!Array.isArray(lane)) throw new TypeError('message_values lane is not allocated');
|
|
628
|
+
lane[pos] = val;
|
|
629
|
+
return this;
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
}
|
|
206
634
|
|
|
207
635
|
/**
|
|
208
636
|
* Get or create a SpanBuffer class for the given schema.
|
|
@@ -217,9 +645,20 @@ const spanBufferClassCache = new WeakMap<LogSchema, SpanBufferConstructor>();
|
|
|
217
645
|
* @returns SpanBufferConstructor with static schema and stats properties
|
|
218
646
|
*/
|
|
219
647
|
//#region smoo/lmao!n/spanbuffer-layout.constructor
|
|
220
|
-
export function getSpanBufferClass<T extends LogSchema>(
|
|
221
|
-
|
|
222
|
-
|
|
648
|
+
export function getSpanBufferClass<T extends LogSchema>(
|
|
649
|
+
schema: T,
|
|
650
|
+
messageLayoutFamily: MessageLayoutFamily = 'mixed',
|
|
651
|
+
messagePhysicalLayout: MessagePhysicalLayout = 'current',
|
|
652
|
+
eagerColumns: EagerColumnDescriptor = EMPTY_EAGER_COLUMNS,
|
|
653
|
+
): SpanBufferConstructor<T> {
|
|
654
|
+
const cacheKey = `${activeMaterializerMode()}:${messageLayoutFamily}:${messagePhysicalLayout}:${eagerColumns.key}`;
|
|
655
|
+
let familyClasses = spanBufferClassCache.get(schema);
|
|
656
|
+
const cached = familyClasses?.get(cacheKey);
|
|
657
|
+
if (
|
|
658
|
+
isSpanBufferConstructorForSchema(cached, schema) &&
|
|
659
|
+
cached.messageLayoutFamily === messageLayoutFamily &&
|
|
660
|
+
cached.messagePhysicalLayout === messagePhysicalLayout
|
|
661
|
+
) {
|
|
223
662
|
return cached;
|
|
224
663
|
}
|
|
225
664
|
|
|
@@ -243,7 +682,7 @@ export function getSpanBufferClass<T extends LogSchema>(schema: T): SpanBufferCo
|
|
|
243
682
|
// 2. _capacity - compared on EVERY write (overflow check)
|
|
244
683
|
// 3. _overflow - checked when overflow occurs
|
|
245
684
|
// 4. timestamp/entry_type - TypedArray refs accessed on EVERY write
|
|
246
|
-
// 5.
|
|
685
|
+
// 5. _nodeIndex/_parent - modified/accessed during span creation
|
|
247
686
|
// 6. _traceRoot - accessed for timestamp anchors on EVERY write
|
|
248
687
|
// 7. _identity/_logBinding - accessed during span operations
|
|
249
688
|
// 8-N. Cold properties - only accessed during Arrow conversion
|
|
@@ -251,14 +690,20 @@ export function getSpanBufferClass<T extends LogSchema>(schema: T): SpanBufferCo
|
|
|
251
690
|
|
|
252
691
|
// Define extension for arrow-builder's class generator
|
|
253
692
|
const extension: ColumnBufferExtension = {
|
|
254
|
-
|
|
693
|
+
preallocatedColumns: eagerColumns.names,
|
|
694
|
+
constructorParams: 'stats, parent, isChained, callsiteMetadata, opMetadata, traceRoot, vocabularyGeneration',
|
|
255
695
|
dependencies: {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
textEncoder,
|
|
696
|
+
copyThreadIdTo,
|
|
697
|
+
getThreadId,
|
|
259
698
|
EMPTY_SCOPE,
|
|
260
699
|
checkCapacityTuning,
|
|
261
700
|
},
|
|
701
|
+
// No-eval counterparts consumed by arrow-builder's closure-composed
|
|
702
|
+
// materializer on runtimes without string codegen (workerd). They MUST
|
|
703
|
+
// mirror constructorPreamble/methods below exactly — see the factories
|
|
704
|
+
// above and spanbuffer-materializer-parity.test.ts.
|
|
705
|
+
closureInit: createSpanBufferClosureInit(messageLayoutFamily, messagePhysicalLayout),
|
|
706
|
+
closureMethods: createSpanBufferClosureMethods(messageLayoutFamily),
|
|
262
707
|
// ==========================================================================
|
|
263
708
|
// GENERATED CONSTRUCTOR PREAMBLE
|
|
264
709
|
// ==========================================================================
|
|
@@ -284,12 +729,11 @@ export function getSpanBufferClass<T extends LogSchema>(schema: T): SpanBufferCo
|
|
|
284
729
|
// V8 IN-OBJECT PROPERTY OPTIMIZATION:
|
|
285
730
|
// Property assignment order determines which properties get fast in-object slots.
|
|
286
731
|
// First ~10-12 properties are stored directly on the object (fastest access).
|
|
287
|
-
// Slots
|
|
288
|
-
// Slots
|
|
289
|
-
// Slots
|
|
290
|
-
// Slots
|
|
291
|
-
// Slots
|
|
292
|
-
// Slots 12+: COLD (Arrow conversion only) - _callsiteMetadata, _opMetadata
|
|
732
|
+
// Slots 0-2: HOTTEST (every log entry) - _writeIndex, _capacity, _overflow
|
|
733
|
+
// Slots 3-6: HOT (storage refs) - timestamp, entry_type/header, message identity, vocabulary
|
|
734
|
+
// Slots 7-10: WARM (tree structure) - _nodeIndex, _topologyGeneration, _parent, _traceRoot
|
|
735
|
+
// Slots 11-14: WARM (context/identity) - _scopeValues, _threadId, _identity, _system
|
|
736
|
+
// Slots 15+: COLD (Arrow/stats/raw message) - metadata, stats, message_values
|
|
293
737
|
// ==========================================================================
|
|
294
738
|
constructorPreamble:
|
|
295
739
|
// Thread-local span counter (per-process/worker, see threadId.ts docs)
|
|
@@ -297,84 +741,133 @@ export function getSpanBufferClass<T extends LogSchema>(schema: T): SpanBufferCo
|
|
|
297
741
|
globalThis.globalSpanCounter = 0;
|
|
298
742
|
}
|
|
299
743
|
const spanId = ++globalThis.globalSpanCounter;
|
|
744
|
+
const threadId = isChained ? parent.thread_id : getThreadId();
|
|
300
745
|
` +
|
|
301
|
-
// Calculate
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const systemSize = (
|
|
746
|
+
// Calculate exact physical system storage once for the generated class.
|
|
747
|
+
(messagePhysicalLayout === 'packed'
|
|
748
|
+
? `const rowHeaderOffset = requestedCapacity * 8;
|
|
749
|
+
const systemSize = (requestedCapacity * 12 + 7) & ~7;
|
|
305
750
|
let systemBuffer;
|
|
306
751
|
let identityView;
|
|
307
|
-
`
|
|
752
|
+
`
|
|
753
|
+
: messageLayoutFamily === 'dynamic-only'
|
|
754
|
+
? `const systemSize = (requestedCapacity * 9 + 7) & ~7;
|
|
755
|
+
let systemBuffer;
|
|
756
|
+
let identityView;
|
|
757
|
+
`
|
|
758
|
+
: messagePhysicalLayout === 'current'
|
|
759
|
+
? `const messageIdOffset = (requestedCapacity * 9 + 1) & ~1;
|
|
760
|
+
const systemSize = (messageIdOffset + requestedCapacity * 2 + 7) & ~7;
|
|
761
|
+
let systemBuffer;
|
|
762
|
+
let identityView;
|
|
763
|
+
`
|
|
764
|
+
: `const logHeaderOffset = (requestedCapacity * 9 + 3) & ~3;
|
|
765
|
+
const systemSize = (logHeaderOffset + requestedCapacity * 4 + 7) & ~7;
|
|
766
|
+
let systemBuffer;
|
|
767
|
+
let identityView;
|
|
768
|
+
`) +
|
|
308
769
|
// CHAINED BUFFER: overflow storage for same logical span - shares parent identity
|
|
309
770
|
`if (isChained) {
|
|
310
771
|
systemBuffer = new ArrayBuffer(systemSize);
|
|
311
772
|
identityView = parent._identity;
|
|
312
773
|
}` +
|
|
313
774
|
// CHILD BUFFER: new span in existing trace - gets identity without traceId
|
|
314
|
-
// (traceId accessed via parent chain walk in trace_id getter)
|
|
315
775
|
` else if (parent) {
|
|
316
776
|
const identitySize = 12;
|
|
317
777
|
systemBuffer = new ArrayBuffer(systemSize + identitySize);
|
|
318
778
|
identityView = new Uint8Array(systemBuffer, systemSize, identitySize);
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
779
|
+
copyThreadIdTo(identityView, 0);
|
|
780
|
+
identityView[8] = spanId;
|
|
781
|
+
identityView[9] = spanId >>> 8;
|
|
782
|
+
identityView[10] = spanId >>> 16;
|
|
783
|
+
identityView[11] = spanId >>> 24;
|
|
322
784
|
}` +
|
|
323
|
-
// ROOT BUFFER: new trace -
|
|
785
|
+
// ROOT BUFFER: new trace - copies the trace-owned canonical bytes once into its public identity.
|
|
324
786
|
` else {
|
|
325
|
-
const
|
|
326
|
-
const identitySize = 13 +
|
|
787
|
+
const traceIdBytes = traceRoot._traceIdBytes;
|
|
788
|
+
const identitySize = 13 + traceIdBytes.length;
|
|
327
789
|
systemBuffer = new ArrayBuffer(systemSize + identitySize);
|
|
328
790
|
identityView = new Uint8Array(systemBuffer, systemSize, identitySize);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
identityView[
|
|
334
|
-
identityView.
|
|
791
|
+
copyThreadIdTo(identityView, 0);
|
|
792
|
+
identityView[8] = spanId;
|
|
793
|
+
identityView[9] = spanId >>> 8;
|
|
794
|
+
identityView[10] = spanId >>> 16;
|
|
795
|
+
identityView[11] = spanId >>> 24;
|
|
796
|
+
identityView[12] = traceIdBytes.length;
|
|
797
|
+
identityView.set(traceIdBytes, 13);
|
|
335
798
|
}
|
|
336
799
|
` +
|
|
337
|
-
// Create
|
|
338
|
-
|
|
800
|
+
// Create exact physical views. Packed classes never create split entry/header views.
|
|
801
|
+
(messagePhysicalLayout === 'packed'
|
|
802
|
+
? `const timestampView = new BigInt64Array(systemBuffer, 0, requestedCapacity);
|
|
803
|
+
const rowHeaderView = new Uint32Array(systemBuffer, rowHeaderOffset, requestedCapacity);
|
|
804
|
+
`
|
|
805
|
+
: `const timestampView = new BigInt64Array(systemBuffer, 0, requestedCapacity);
|
|
339
806
|
const entryTypeView = new Uint8Array(systemBuffer, requestedCapacity * 8, requestedCapacity);
|
|
340
|
-
timestampView.fill(0n);
|
|
341
|
-
entryTypeView.fill(0);
|
|
342
807
|
` +
|
|
343
|
-
|
|
808
|
+
(messageLayoutFamily === 'dynamic-only'
|
|
809
|
+
? ''
|
|
810
|
+
: messagePhysicalLayout === 'current'
|
|
811
|
+
? ` const messageIdView = new Uint16Array(systemBuffer, messageIdOffset, requestedCapacity);
|
|
812
|
+
`
|
|
813
|
+
: ` const logHeaderView = new Uint32Array(systemBuffer, logHeaderOffset, requestedCapacity);
|
|
814
|
+
`)) +
|
|
815
|
+
// Assign properties in optimal order for V8 in-object slots.
|
|
344
816
|
`this._writeIndex = 0;
|
|
345
817
|
this._capacity = requestedCapacity;
|
|
346
818
|
this._overflow = undefined;
|
|
347
819
|
this.timestamp = timestampView;
|
|
348
|
-
|
|
349
|
-
|
|
820
|
+
` +
|
|
821
|
+
(messagePhysicalLayout === 'packed'
|
|
822
|
+
? ` this._rowHeaders = rowHeaderView;
|
|
823
|
+
`
|
|
824
|
+
: ` this.entry_type = entryTypeView;
|
|
825
|
+
` +
|
|
826
|
+
(messageLayoutFamily === 'dynamic-only'
|
|
827
|
+
? ''
|
|
828
|
+
: messagePhysicalLayout === 'current'
|
|
829
|
+
? ` this._messageIds = messageIdView;
|
|
830
|
+
`
|
|
831
|
+
: ` this._logHeaders = logHeaderView;
|
|
832
|
+
`)) +
|
|
833
|
+
` this._vocabularyGeneration = vocabularyGeneration;
|
|
834
|
+
` +
|
|
835
|
+
(messageLayoutFamily === 'static-only'
|
|
836
|
+
? ` this._spanName = undefined;
|
|
837
|
+
this._terminalMessage = undefined;
|
|
838
|
+
`
|
|
839
|
+
: messageLayoutFamily === 'dynamic-only'
|
|
840
|
+
? ` this._spanName = undefined;
|
|
841
|
+
`
|
|
842
|
+
: '') +
|
|
843
|
+
` this._nodeIndex = 4294967295;
|
|
844
|
+
this._topologyGeneration = 0;
|
|
350
845
|
this._parent = isChained ? parent._parent : parent;
|
|
351
846
|
this._traceRoot = traceRoot;
|
|
352
847
|
this._scopeValues = parent ? parent._scopeValues : EMPTY_SCOPE;
|
|
848
|
+
this._threadId = threadId;
|
|
353
849
|
this._identity = identityView;
|
|
354
850
|
this._system = systemBuffer;
|
|
355
851
|
this._callsiteMetadata = callsiteMetadata;
|
|
356
852
|
this._opMetadata = opMetadata;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
853
|
+
this._statsSealed = false;
|
|
854
|
+
this._statsReservedRows = isChained ? 0 : 2;
|
|
855
|
+
` +
|
|
856
|
+
(messageLayoutFamily === 'static-only'
|
|
857
|
+
? ''
|
|
858
|
+
: ` this.message_values = new Array(requestedCapacity);
|
|
859
|
+
`) +
|
|
860
|
+
' ',
|
|
861
|
+
// Generated identity methods use canonical primitives/direct offsets without temporary views.
|
|
365
862
|
methods: `get span_id() {
|
|
366
|
-
|
|
863
|
+
const b = this._identity;
|
|
864
|
+
return b ? (b[8] | (b[9] << 8) | (b[10] << 16) | (b[11] << 24)) >>> 0 : 0;
|
|
367
865
|
}
|
|
368
866
|
get thread_id() {
|
|
369
|
-
return this.
|
|
867
|
+
return this._threadId;
|
|
370
868
|
}
|
|
371
869
|
get trace_id() {
|
|
372
|
-
|
|
373
|
-
while (current._parent) { current = current._parent; }
|
|
374
|
-
if (!current._identity) { return undefined; }
|
|
375
|
-
const len = current._identity[12];
|
|
376
|
-
const traceIdBytes = current._identity.subarray(13, 13 + len);
|
|
377
|
-
return textDecoder.decode(traceIdBytes);
|
|
870
|
+
return this._traceRoot.trace_id;
|
|
378
871
|
}
|
|
379
872
|
get _spanStartTime() {
|
|
380
873
|
return this.timestamp[0];
|
|
@@ -403,42 +896,90 @@ export function getSpanBufferClass<T extends LogSchema>(schema: T): SpanBufferCo
|
|
|
403
896
|
isParentOf(other) { return this === other._parent; }
|
|
404
897
|
isChildOf(other) { return this._parent === other; }
|
|
405
898
|
copyThreadIdTo(dest, offset) {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
899
|
+
const source = this._identity;
|
|
900
|
+
if (source) {
|
|
901
|
+
dest[offset] = source[0];
|
|
902
|
+
dest[offset + 1] = source[1];
|
|
903
|
+
dest[offset + 2] = source[2];
|
|
904
|
+
dest[offset + 3] = source[3];
|
|
905
|
+
dest[offset + 4] = source[4];
|
|
906
|
+
dest[offset + 5] = source[5];
|
|
907
|
+
dest[offset + 6] = source[6];
|
|
908
|
+
dest[offset + 7] = source[7];
|
|
410
909
|
} else {
|
|
411
|
-
|
|
910
|
+
dest.fill(0, offset, offset + 8);
|
|
412
911
|
}
|
|
413
912
|
}
|
|
414
913
|
copyParentThreadIdTo(dest, offset) {
|
|
415
|
-
this._parent
|
|
914
|
+
if (this._parent) this._parent.copyThreadIdTo(dest, offset);
|
|
915
|
+
else dest.fill(0, offset, offset + 8);
|
|
416
916
|
}
|
|
417
917
|
get _logSchema() { return this.constructor.schema; }
|
|
918
|
+
get _messageLayoutFamily() { return this.constructor.messageLayoutFamily; }
|
|
919
|
+
get _messagePhysicalLayout() { return this.constructor.messagePhysicalLayout; }
|
|
418
920
|
get _columns() { return this.constructor.schema._columns; }
|
|
419
921
|
get _stats() { return this.constructor.stats; }
|
|
922
|
+
_sealStats() {
|
|
923
|
+
if (this._statsSealed) return;
|
|
924
|
+
const completedRows = this._writeIndex - this._statsReservedRows;
|
|
925
|
+
if (completedRows > 0) this.constructor.stats.totalWrites += completedRows;
|
|
926
|
+
this._statsSealed = true;
|
|
927
|
+
}
|
|
928
|
+
_sealStatsChain() {
|
|
929
|
+
let current = this;
|
|
930
|
+
while (current) {
|
|
931
|
+
current._sealStats();
|
|
932
|
+
current = current._overflow;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
420
935
|
getOrCreateOverflow() {
|
|
421
936
|
if (this._overflow) return this._overflow;
|
|
937
|
+
this._sealStats();
|
|
422
938
|
const tracer = this._traceRoot.tracer;
|
|
423
939
|
tracer.onStatsWillResetFor(this);
|
|
424
940
|
checkCapacityTuning(this.constructor.stats);
|
|
425
941
|
return tracer.bufferStrategy.createOverflowBuffer(this);
|
|
426
942
|
}
|
|
943
|
+
${
|
|
944
|
+
messageLayoutFamily === 'static-only'
|
|
945
|
+
? `message(pos, val) {
|
|
946
|
+
if (pos === 0) this._spanName = val;
|
|
947
|
+
else if (pos === 1) this._terminalMessage = val;
|
|
948
|
+
else throw new RangeError('Static-only buffers only accept raw system messages at rows 0 and 1');
|
|
949
|
+
return this;
|
|
950
|
+
}`
|
|
951
|
+
: `message(pos, val) {
|
|
952
|
+
this.message_values[pos] = val;
|
|
953
|
+
return this;
|
|
954
|
+
}`
|
|
955
|
+
}
|
|
427
956
|
`,
|
|
428
957
|
};
|
|
429
958
|
|
|
959
|
+
// Storage schema identity partitions source schema/family/physical classes; the extension cache key
|
|
960
|
+
// partitions eager-column selections without adding another dedicated cache object.
|
|
961
|
+
const storageSchema = getStorageSchema(schema, messageLayoutFamily, messagePhysicalLayout);
|
|
962
|
+
|
|
430
963
|
// Generate class with arrow-builder
|
|
431
|
-
const generatedClass = getColumnBufferClass(
|
|
964
|
+
const generatedClass = getColumnBufferClass(storageSchema, extension, storageSchema);
|
|
432
965
|
if (!isGeneratedSpanBufferClass<T>(generatedClass)) {
|
|
433
966
|
throw new TypeError('Generated column buffer is missing SpanBuffer methods');
|
|
434
967
|
}
|
|
435
968
|
|
|
436
|
-
//
|
|
437
|
-
//
|
|
438
|
-
const SpanBufferClass = createSpanBufferConstructor(
|
|
969
|
+
// Initialize immutable static discriminators before publishing the constructor in the LMAO cache.
|
|
970
|
+
// The mutable stats object remains shared by every instance of this exact class dimension.
|
|
971
|
+
const SpanBufferClass = createSpanBufferConstructor(
|
|
972
|
+
schema,
|
|
973
|
+
messageLayoutFamily,
|
|
974
|
+
messagePhysicalLayout,
|
|
975
|
+
generatedClass,
|
|
976
|
+
eagerColumns,
|
|
977
|
+
);
|
|
439
978
|
|
|
440
979
|
// Cache for future use
|
|
441
|
-
|
|
980
|
+
familyClasses ??= new Map();
|
|
981
|
+
familyClasses.set(cacheKey, SpanBufferClass);
|
|
982
|
+
spanBufferClassCache.set(schema, familyClasses);
|
|
442
983
|
|
|
443
984
|
return SpanBufferClass;
|
|
444
985
|
}
|
|
@@ -460,7 +1001,15 @@ export function getSpanBufferClass<T extends LogSchema>(schema: T): SpanBufferCo
|
|
|
460
1001
|
*
|
|
461
1002
|
* @returns SpanBuffer with typed setters for schema fields
|
|
462
1003
|
*/
|
|
463
|
-
const
|
|
1004
|
+
export const MIN_ADAPTIVE_BUFFER_CAPACITY = 8;
|
|
1005
|
+
|
|
1006
|
+
export function resolveSpanBufferCapacity(explicitCapacity: number | undefined, adaptiveCapacity: number): number {
|
|
1007
|
+
if (explicitCapacity === undefined) return Math.max(MIN_ADAPTIVE_BUFFER_CAPACITY, adaptiveCapacity);
|
|
1008
|
+
if (!Number.isSafeInteger(explicitCapacity) || explicitCapacity < 2) {
|
|
1009
|
+
throw new RangeError('Explicit span buffer capacity must be a safe integer of at least 2');
|
|
1010
|
+
}
|
|
1011
|
+
return explicitCapacity;
|
|
1012
|
+
}
|
|
464
1013
|
|
|
465
1014
|
//#region smoo/lmao!n/spanbuffer-layout.create-root
|
|
466
1015
|
export function createSpanBuffer<T extends LogSchema>(
|
|
@@ -468,27 +1017,39 @@ export function createSpanBuffer<T extends LogSchema>(
|
|
|
468
1017
|
traceRoot: ITraceRoot,
|
|
469
1018
|
opMetadata: OpMetadata,
|
|
470
1019
|
capacity?: number,
|
|
1020
|
+
plannedClass?: SpanBufferConstructor<T>,
|
|
471
1021
|
): SpanBuffer<T> {
|
|
472
|
-
const
|
|
1022
|
+
const metadataPlan = opMetadata._physicalLayoutPlan;
|
|
1023
|
+
const metadataSpanBufferClass = metadataPlan?.SpanBufferClass;
|
|
1024
|
+
if (metadataSpanBufferClass !== undefined && !isSpanBufferConstructorForSchema(metadataSpanBufferClass, schema)) {
|
|
1025
|
+
throw new TypeError('Planned SpanBuffer class does not match schema');
|
|
1026
|
+
}
|
|
1027
|
+
const plannedSpanBufferClass = plannedClass ?? metadataSpanBufferClass;
|
|
1028
|
+
const SpanBufferClass = plannedSpanBufferClass ?? getSpanBufferClass(schema);
|
|
473
1029
|
const stats = SpanBufferClass.stats;
|
|
474
1030
|
|
|
475
|
-
//
|
|
476
|
-
const actualCapacity =
|
|
1031
|
+
// Compiler-planned capacities are validated when the runtime hint is decoded. Keep direct external calls strict.
|
|
1032
|
+
const actualCapacity =
|
|
1033
|
+
plannedSpanBufferClass === undefined
|
|
1034
|
+
? resolveSpanBufferCapacity(capacity, stats.capacity)
|
|
1035
|
+
: (capacity ?? Math.max(MIN_ADAPTIVE_BUFFER_CAPACITY, stats.capacity));
|
|
477
1036
|
|
|
478
1037
|
// Track non-chained buffer creation for capacity tuning
|
|
479
1038
|
stats.spansCreated++;
|
|
480
1039
|
|
|
481
|
-
// Create root buffer (no parent)
|
|
482
|
-
|
|
483
|
-
return new SpanBufferClass(
|
|
1040
|
+
// Create root buffer (no parent), then register its stable logical node.
|
|
1041
|
+
const buffer = new SpanBufferClass(
|
|
484
1042
|
actualCapacity,
|
|
485
1043
|
stats,
|
|
486
|
-
undefined,
|
|
487
|
-
false,
|
|
488
|
-
opMetadata,
|
|
489
|
-
opMetadata,
|
|
490
|
-
traceRoot,
|
|
1044
|
+
undefined,
|
|
1045
|
+
false,
|
|
1046
|
+
opMetadata,
|
|
1047
|
+
opMetadata,
|
|
1048
|
+
traceRoot,
|
|
1049
|
+
metadataPlan?.vocabularyGeneration ?? getVocabularyGeneration(),
|
|
491
1050
|
);
|
|
1051
|
+
traceRoot._topology.registerRoot(buffer);
|
|
1052
|
+
return buffer;
|
|
492
1053
|
}
|
|
493
1054
|
//#endregion smoo/lmao!n/spanbuffer-layout.create-root
|
|
494
1055
|
|
|
@@ -520,10 +1081,12 @@ export function createOverflowBuffer<T extends LogSchema>(buffer: SpanBuffer<T>)
|
|
|
520
1081
|
buffer._callsiteMetadata,
|
|
521
1082
|
buffer._opMetadata,
|
|
522
1083
|
buffer._traceRoot, // traceRoot from parent
|
|
1084
|
+
buffer._vocabularyGeneration,
|
|
523
1085
|
);
|
|
524
1086
|
|
|
525
1087
|
// Link current buffer to next
|
|
526
1088
|
buffer._overflow = nextBuffer;
|
|
1089
|
+
buffer._traceRoot._topology.adoptOverflow(buffer, nextBuffer);
|
|
527
1090
|
|
|
528
1091
|
return nextBuffer;
|
|
529
1092
|
}
|
|
@@ -554,7 +1117,8 @@ export function createChildSpanBuffer<T extends LogSchema>(
|
|
|
554
1117
|
capacity?: number,
|
|
555
1118
|
): SpanBuffer<T> {
|
|
556
1119
|
const stats = SpanBufferClass.stats;
|
|
557
|
-
|
|
1120
|
+
// Child capacities arrive through a validated callsite plan; preserve exact values including 2..7.
|
|
1121
|
+
const actualCapacity = capacity ?? Math.max(MIN_ADAPTIVE_BUFFER_CAPACITY, stats.capacity);
|
|
558
1122
|
|
|
559
1123
|
// Track non-chained buffer creation for capacity tuning
|
|
560
1124
|
stats.spansCreated++;
|
|
@@ -568,8 +1132,10 @@ export function createChildSpanBuffer<T extends LogSchema>(
|
|
|
568
1132
|
callsiteMetadata, // callsiteMetadata - CALLER's op metadata (for row 0)
|
|
569
1133
|
opMetadata, // opMetadata - EXECUTING op metadata (for rows 1+)
|
|
570
1134
|
parentBuffer._traceRoot, // traceRoot from parent
|
|
1135
|
+
opMetadata._physicalLayoutPlan?.vocabularyGeneration ?? getVocabularyGeneration(),
|
|
571
1136
|
);
|
|
572
1137
|
|
|
1138
|
+
parentBuffer._traceRoot._topology.registerChild(parentBuffer, childBuffer);
|
|
573
1139
|
return childBuffer;
|
|
574
1140
|
}
|
|
575
1141
|
//#endregion smoo/lmao!n/spanbuffer-layout.create-child
|