@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
|
@@ -7,14 +7,19 @@
|
|
|
7
7
|
* - Text columns: Plain strings without dictionary
|
|
8
8
|
* - Zero-copy wrap TypedArrays as Arrow vectors
|
|
9
9
|
*/
|
|
10
|
-
import { clearBitRange, compareStrings, createSortedDictionary, DictionaryBuilder, getMaskTransform, sortInPlace, } from '@smoothbricks/arrow-builder';
|
|
10
|
+
import { clearBitRange, compareStrings, countNulls, createSortedDictionary, DictionaryBuilder, getMaskTransform, sortInPlace, } from '@smoothbricks/arrow-builder';
|
|
11
11
|
import { batchType, binary, bool, Column, dictionary, float64, int8, TimeUnit, tableFromColumns, timestamp, uint8, uint16, uint32, uint64, utf8, } from '@uwdata/flechette';
|
|
12
12
|
import { createCapacityStatsTable } from './arrow/capacityStats.js';
|
|
13
13
|
import { buildSortedCategoryDictionary, buildTextDictionary } from './arrow/dictionaries.js';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
14
|
+
import { makeArrowColumn, } from './arrow/flechette.js';
|
|
15
|
+
import { createArrowLease } from './arrow/lease.js';
|
|
16
|
+
import { calculateUtf8Offsets, combineColumnChunks, concatenateFloat64Arrays, concatenateNullBitmaps, concatenateUint8Arrays, encodeUtf8Strings, getArrowFieldName, } from './arrow/utils.js';
|
|
17
|
+
import { appendVocabularyDictionarySuffix, getVocabularyDictionaryPrefix, PREBUILT_ENTRY_TYPE_DICTIONARY, } from './arrow/vocabularyDictionary.js';
|
|
18
|
+
import { resolveEnumLookupDescriptor } from './enumMetadata.js';
|
|
19
|
+
import { resolveEntryType } from './resolveMessage.js';
|
|
20
|
+
import { ENTRY_TYPE_ERROR, ENTRY_TYPE_SPAN_START, ENTRY_TYPE_TRACE, SYSTEM_SCHEMA_FIELD_NAMES, } from './schema/systemSchema.js';
|
|
21
|
+
import { getBinaryEncoder, getEnumUtf8, getSchemaType } from './schema/typeGuards.js';
|
|
22
|
+
import { walkSpanTree } from './traceTopology.js';
|
|
18
23
|
import { globalUtf8Cache } from './utf8Cache.js';
|
|
19
24
|
const DictBuilder = DictionaryBuilder;
|
|
20
25
|
const F64Array = Float64Array;
|
|
@@ -83,15 +88,20 @@ function appendTables(base, extra) {
|
|
|
83
88
|
}
|
|
84
89
|
return tableFromColumns(columns);
|
|
85
90
|
}
|
|
86
|
-
function
|
|
87
|
-
|
|
91
|
+
function resolveColumnName(buffer, outputName, remaps) {
|
|
92
|
+
return remaps.get(buffer)?.sourceNames[outputName] ?? outputName;
|
|
93
|
+
}
|
|
94
|
+
function getAllocatedStringColumn(buffer, columnName, remaps) {
|
|
95
|
+
const sourceName = remaps ? resolveColumnName(buffer, columnName, remaps) : columnName;
|
|
96
|
+
const column = buffer.getColumnIfAllocated(sourceName);
|
|
88
97
|
if (!Array.isArray(column)) {
|
|
89
98
|
return undefined;
|
|
90
99
|
}
|
|
91
100
|
return isStringArray(column) ? column : undefined;
|
|
92
101
|
}
|
|
93
|
-
function getAllocatedBinaryColumn(buffer, columnName) {
|
|
94
|
-
const
|
|
102
|
+
function getAllocatedBinaryColumn(buffer, columnName, remaps) {
|
|
103
|
+
const sourceName = remaps ? resolveColumnName(buffer, columnName, remaps) : columnName;
|
|
104
|
+
const column = buffer.getColumnIfAllocated(sourceName);
|
|
95
105
|
return Array.isArray(column) ? column : undefined;
|
|
96
106
|
}
|
|
97
107
|
//#region smoo/lmao!n/scope-attributes.arrow-fill
|
|
@@ -99,16 +109,19 @@ function getAllocatedBinaryColumn(buffer, columnName) {
|
|
|
99
109
|
// Arrow conversion. These typed readers pull from the buffer's immutable _scopeValues; the
|
|
100
110
|
// per-column fill loops below call them so a row with a direct write keeps its value and scope
|
|
101
111
|
// only fills the gaps.
|
|
102
|
-
function getStringScopeValue(buffer, fieldName) {
|
|
103
|
-
const
|
|
112
|
+
function getStringScopeValue(buffer, fieldName, remaps) {
|
|
113
|
+
const sourceName = remaps ? resolveColumnName(buffer, fieldName, remaps) : fieldName;
|
|
114
|
+
const value = buffer._scopeValues?.[sourceName];
|
|
104
115
|
return typeof value === 'string' ? value : undefined;
|
|
105
116
|
}
|
|
106
|
-
function getNumberScopeValue(buffer, fieldName) {
|
|
107
|
-
const
|
|
117
|
+
function getNumberScopeValue(buffer, fieldName, remaps) {
|
|
118
|
+
const sourceName = remaps ? resolveColumnName(buffer, fieldName, remaps) : fieldName;
|
|
119
|
+
const value = buffer._scopeValues?.[sourceName];
|
|
108
120
|
return typeof value === 'number' ? value : undefined;
|
|
109
121
|
}
|
|
110
|
-
function getBooleanScopeValue(buffer, fieldName) {
|
|
111
|
-
const
|
|
122
|
+
function getBooleanScopeValue(buffer, fieldName, remaps) {
|
|
123
|
+
const sourceName = remaps ? resolveColumnName(buffer, fieldName, remaps) : fieldName;
|
|
124
|
+
const value = buffer._scopeValues?.[sourceName];
|
|
112
125
|
return typeof value === 'boolean' ? value : undefined;
|
|
113
126
|
}
|
|
114
127
|
//#endregion smoo/lmao!n/scope-attributes.arrow-fill
|
|
@@ -122,12 +135,166 @@ function isStringArray(value) {
|
|
|
122
135
|
return Array.isArray(value) && value.every((entry) => typeof entry === 'string' || entry == null);
|
|
123
136
|
}
|
|
124
137
|
function indexTypeForCount(count) {
|
|
125
|
-
if (count <=
|
|
138
|
+
if (count <= 0x100)
|
|
126
139
|
return uint8();
|
|
127
|
-
if (count <=
|
|
140
|
+
if (count <= 65536)
|
|
128
141
|
return uint16();
|
|
129
142
|
return uint32();
|
|
130
143
|
}
|
|
144
|
+
function assertStaticMessageKind(buffer, row, entryType, denseIndex) {
|
|
145
|
+
const generation = buffer._vocabularyGeneration;
|
|
146
|
+
if (denseIndex >= generation.ids.length) {
|
|
147
|
+
throw new Error(`Invalid vocabulary dense index ${denseIndex} for generation ${generation.generation}`);
|
|
148
|
+
}
|
|
149
|
+
const expectedKind = entryType === ENTRY_TYPE_SPAN_START ? 2 : entryType >= ENTRY_TYPE_TRACE && entryType <= ENTRY_TYPE_ERROR ? 1 : 0;
|
|
150
|
+
if (expectedKind === 0) {
|
|
151
|
+
throw new Error(`Entry type ${entryType} at row ${row} cannot carry a static vocabulary identity`);
|
|
152
|
+
}
|
|
153
|
+
const actualKind = generation.kindTags[denseIndex];
|
|
154
|
+
if (actualKind !== expectedKind) {
|
|
155
|
+
throw new Error(`Vocabulary kind ${actualKind} at dense index ${denseIndex} does not match entry type ${entryType} at row ${row}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function buildMessageColumn(buffers, totalRows, dictionaryId, materializeEntryTypes = true) {
|
|
159
|
+
let generation = buffers[0]._vocabularyGeneration;
|
|
160
|
+
for (let index = 1; index < buffers.length; index++) {
|
|
161
|
+
const candidate = buffers[index]._vocabularyGeneration;
|
|
162
|
+
if (candidate.generation > generation.generation)
|
|
163
|
+
generation = candidate;
|
|
164
|
+
}
|
|
165
|
+
const prefix = getVocabularyDictionaryPrefix(generation);
|
|
166
|
+
const indices = new Uint32Array(totalRows);
|
|
167
|
+
const entryTypeIndices = materializeEntryTypes ? new Int8Array(totalRows) : undefined;
|
|
168
|
+
const nullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
|
|
169
|
+
let nullCount = 0;
|
|
170
|
+
let rowOffset = 0;
|
|
171
|
+
let suffixValues;
|
|
172
|
+
let suffixIndices;
|
|
173
|
+
for (const buffer of buffers) {
|
|
174
|
+
const plannedStorage = buffer._opMetadata._physicalLayoutPlan?.arrowExposure.messageIdentityStorage;
|
|
175
|
+
const messageIdentityStorage = plannedStorage ??
|
|
176
|
+
(buffer._messagePhysicalLayout === 'current'
|
|
177
|
+
? 'local-u16'
|
|
178
|
+
: buffer._messagePhysicalLayout === 'specialized'
|
|
179
|
+
? 'global-u32'
|
|
180
|
+
: 'packed-row-headers');
|
|
181
|
+
for (let row = 0; row < buffer._writeIndex; row++) {
|
|
182
|
+
const outputRow = rowOffset + row;
|
|
183
|
+
const hasDedicatedMessage = (row === 0 && buffer._spanName !== undefined) || (row === 1 && buffer._terminalMessage !== undefined);
|
|
184
|
+
let dictionaryIndex;
|
|
185
|
+
let entryType;
|
|
186
|
+
if (messageIdentityStorage === 'local-u16') {
|
|
187
|
+
entryType = resolveEntryType(buffer, row);
|
|
188
|
+
const localId = buffer._messageIds?.[row];
|
|
189
|
+
const rawMessage = buffer.message_values?.[row];
|
|
190
|
+
if (row === 0 && typeof buffer._spanName === 'number') {
|
|
191
|
+
if ((localId !== undefined && localId > 0) || rawMessage !== undefined) {
|
|
192
|
+
throw new Error(`Local row ${row} has conflicting static message identities`);
|
|
193
|
+
}
|
|
194
|
+
dictionaryIndex = buffer._spanName;
|
|
195
|
+
}
|
|
196
|
+
else if (localId !== undefined && localId > 0) {
|
|
197
|
+
if (hasDedicatedMessage || rawMessage !== undefined) {
|
|
198
|
+
throw new Error(`Local row ${row} has conflicting static and raw message storage`);
|
|
199
|
+
}
|
|
200
|
+
dictionaryIndex = buffer._opMetadata._physicalLayoutPlan?.localMessageDictionary[localId - 1];
|
|
201
|
+
if (dictionaryIndex === undefined)
|
|
202
|
+
throw new Error(`Missing local message dictionary entry ${localId}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else if (messageIdentityStorage === 'global-u32') {
|
|
206
|
+
entryType = resolveEntryType(buffer, row);
|
|
207
|
+
const encodedDenseIndex = buffer._logHeaders?.[row];
|
|
208
|
+
if (encodedDenseIndex !== undefined && encodedDenseIndex > 0) {
|
|
209
|
+
if (hasDedicatedMessage || buffer.message_values?.[row] !== undefined) {
|
|
210
|
+
throw new Error(`Global row ${row} has conflicting static and raw message storage`);
|
|
211
|
+
}
|
|
212
|
+
dictionaryIndex = encodedDenseIndex - 1;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
const rowHeaders = buffer._rowHeaders;
|
|
217
|
+
if (rowHeaders === undefined)
|
|
218
|
+
throw new TypeError('Packed message layout is missing row headers');
|
|
219
|
+
const header = rowHeaders[row];
|
|
220
|
+
entryType = header & 0xff;
|
|
221
|
+
const encodedDenseIndex = header >>> 8;
|
|
222
|
+
if (encodedDenseIndex !== 0) {
|
|
223
|
+
if (hasDedicatedMessage) {
|
|
224
|
+
throw new Error(`Packed row ${row} has conflicting static and dedicated message storage`);
|
|
225
|
+
}
|
|
226
|
+
dictionaryIndex = encodedDenseIndex - 1;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const dedicatedDenseIndex = row === 0 && typeof buffer._spanName === 'number' ? buffer._spanName : undefined;
|
|
230
|
+
if (dedicatedDenseIndex !== undefined) {
|
|
231
|
+
if (buffer.message_values?.[row] !== undefined) {
|
|
232
|
+
throw new Error(`Row ${row} has conflicting dedicated static and raw message storage`);
|
|
233
|
+
}
|
|
234
|
+
dictionaryIndex ??= dedicatedDenseIndex;
|
|
235
|
+
}
|
|
236
|
+
if (entryTypeIndices !== undefined)
|
|
237
|
+
entryTypeIndices[outputRow] = entryType;
|
|
238
|
+
if (dictionaryIndex !== undefined) {
|
|
239
|
+
assertStaticMessageKind(buffer, row, entryType, dictionaryIndex);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
const message = row === 0 && typeof buffer._spanName === 'string'
|
|
243
|
+
? buffer._spanName
|
|
244
|
+
: row === 1 && buffer._terminalMessage !== undefined
|
|
245
|
+
? buffer._terminalMessage
|
|
246
|
+
: buffer.message_values?.[row];
|
|
247
|
+
if (message === undefined) {
|
|
248
|
+
nullCount++;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const staticIndex = prefix.valueToDenseIndex.get(message);
|
|
252
|
+
if (staticIndex !== undefined) {
|
|
253
|
+
dictionaryIndex = staticIndex;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
let dynamicIndex = suffixIndices?.get(message);
|
|
257
|
+
if (dynamicIndex === undefined) {
|
|
258
|
+
suffixValues ??= [];
|
|
259
|
+
suffixIndices ??= new Map();
|
|
260
|
+
dynamicIndex = suffixValues.length;
|
|
261
|
+
suffixValues.push(message);
|
|
262
|
+
suffixIndices.set(message, dynamicIndex);
|
|
263
|
+
}
|
|
264
|
+
dictionaryIndex = prefix.length + dynamicIndex;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
indices[outputRow] = dictionaryIndex;
|
|
268
|
+
nullBitmap[outputRow >>> 3] |= 1 << (outputRow & 7);
|
|
269
|
+
}
|
|
270
|
+
rowOffset += buffer._writeIndex;
|
|
271
|
+
}
|
|
272
|
+
let messageDictionary = prefix.column;
|
|
273
|
+
if (suffixValues !== undefined) {
|
|
274
|
+
const encoded = globalUtf8Cache.encodeMany(suffixValues);
|
|
275
|
+
const suffix = buildColumn(buildData({
|
|
276
|
+
type: utf8(),
|
|
277
|
+
offset: 0,
|
|
278
|
+
length: suffixValues.length,
|
|
279
|
+
nullCount: 0,
|
|
280
|
+
valueOffsets: encoded.offsets,
|
|
281
|
+
data: encoded.data,
|
|
282
|
+
}));
|
|
283
|
+
messageDictionary = appendVocabularyDictionarySuffix(prefix, suffix, suffixValues);
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
column: buildColumn(buildData({
|
|
287
|
+
type: dictionaryId === undefined ? dictionary(utf8(), uint32()) : dictionary(utf8(), uint32(), false, dictionaryId),
|
|
288
|
+
offset: 0,
|
|
289
|
+
length: totalRows,
|
|
290
|
+
nullCount,
|
|
291
|
+
data: indices,
|
|
292
|
+
nullBitmap: nullCount > 0 ? nullBitmap : undefined,
|
|
293
|
+
dictionary: messageDictionary,
|
|
294
|
+
})),
|
|
295
|
+
entryTypeIndices,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
131
298
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
132
299
|
// Shared metadata column helpers (used by both buildMetadataColumnsWithFields
|
|
133
300
|
// and convertBuffersWithSharedDicts to avoid duplication)
|
|
@@ -209,57 +376,73 @@ function buildNonDictIdentityColumns(buffers, totalRows, fields, vectors) {
|
|
|
209
376
|
nullBitmap: parentSpanIdNullCount > 0 ? parentSpanIdNulls : undefined,
|
|
210
377
|
})));
|
|
211
378
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
379
|
+
function buildTimestampColumn(buffers, totalRows, fields, vectors, borrowChunks = false) {
|
|
380
|
+
const timestampType = timestamp(TimeUnit.NANOSECOND);
|
|
381
|
+
fields.push('timestamp');
|
|
382
|
+
if (borrowChunks) {
|
|
383
|
+
const chunks = buffers.map((buffer) => buildColumn(buildData({
|
|
384
|
+
type: timestampType,
|
|
385
|
+
offset: 0,
|
|
386
|
+
length: buffer._writeIndex,
|
|
387
|
+
nullCount: 0,
|
|
388
|
+
data: buffer.timestamp.subarray(0, buffer._writeIndex),
|
|
389
|
+
})));
|
|
390
|
+
vectors.push(combineColumnChunks(chunks));
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
216
393
|
const allTimestamps = new BigInt64Array(totalRows);
|
|
217
394
|
let offset = 0;
|
|
218
|
-
for (const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
allTimestamps.set(buf.timestamp.subarray(0, buf._writeIndex), offset);
|
|
223
|
-
offset += buf._writeIndex;
|
|
395
|
+
for (const buffer of buffers) {
|
|
396
|
+
allTimestamps.set(buffer.timestamp.subarray(0, buffer._writeIndex), offset);
|
|
397
|
+
offset += buffer._writeIndex;
|
|
224
398
|
}
|
|
225
|
-
|
|
226
|
-
vectors.push(buildColumn(buildData({
|
|
227
|
-
type: timestamp(TimeUnit.NANOSECOND),
|
|
228
|
-
offset: 0,
|
|
229
|
-
length: totalRows,
|
|
230
|
-
nullCount: 0,
|
|
231
|
-
data: allTimestamps,
|
|
232
|
-
})));
|
|
399
|
+
vectors.push(buildColumn(buildData({ type: timestampType, offset: 0, length: totalRows, nullCount: 0, data: allTimestamps })));
|
|
233
400
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
401
|
+
function canBorrowEntryTypeChunks(buffers, borrowChunks) {
|
|
402
|
+
return (borrowChunks &&
|
|
403
|
+
buffers.every((buffer) => {
|
|
404
|
+
const declared = buffer._opMetadata._physicalLayoutPlan?.arrowExposure.entryTypeStorage;
|
|
405
|
+
return declared === 'borrowed-u8' || (declared === undefined && buffer.entry_type !== undefined);
|
|
406
|
+
}));
|
|
407
|
+
}
|
|
408
|
+
function buildEntryTypeColumn(buffers, totalRows, fields, vectors, dictType, borrowChunks = false, classifiedEntryTypes) {
|
|
409
|
+
const entryTypeDictionary = PREBUILT_ENTRY_TYPE_DICTIONARY;
|
|
410
|
+
const type = dictType ?? dictionary(utf8(), int8());
|
|
411
|
+
fields.push('entry_type');
|
|
412
|
+
if (canBorrowEntryTypeChunks(buffers, borrowChunks)) {
|
|
413
|
+
const chunks = buffers.map((buffer) => {
|
|
414
|
+
const source = buffer.entry_type;
|
|
415
|
+
if (source === undefined)
|
|
416
|
+
throw new TypeError('Current/specialized buffer is missing entry types');
|
|
417
|
+
const values = new Int8Array(source.buffer, source.byteOffset, buffer._writeIndex);
|
|
418
|
+
return buildColumn(buildData({
|
|
419
|
+
type,
|
|
420
|
+
offset: 0,
|
|
421
|
+
length: buffer._writeIndex,
|
|
422
|
+
nullCount: 0,
|
|
423
|
+
data: values,
|
|
424
|
+
dictionary: entryTypeDictionary,
|
|
425
|
+
}));
|
|
426
|
+
});
|
|
427
|
+
vectors.push(combineColumnChunks(chunks));
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const entryTypeIndices = classifiedEntryTypes ?? new Int8Array(totalRows);
|
|
431
|
+
if (classifiedEntryTypes === undefined) {
|
|
432
|
+
let offset = 0;
|
|
433
|
+
for (const buffer of buffers) {
|
|
434
|
+
for (let row = 0; row < buffer._writeIndex; row++) {
|
|
435
|
+
entryTypeIndices[offset++] = resolveEntryType(buffer, row);
|
|
436
|
+
}
|
|
243
437
|
}
|
|
244
|
-
entryTypeIndices.set(buf.entry_type.subarray(0, buf._writeIndex), offset);
|
|
245
|
-
offset += buf._writeIndex;
|
|
246
438
|
}
|
|
247
|
-
const entryTypeDictData = buildData({
|
|
248
|
-
type: utf8(),
|
|
249
|
-
offset: 0,
|
|
250
|
-
length: ENTRY_TYPE_NAMES.length,
|
|
251
|
-
nullCount: 0,
|
|
252
|
-
valueOffsets: calculateUtf8Offsets(ENTRY_TYPE_NAMES),
|
|
253
|
-
data: encodeUtf8Strings(ENTRY_TYPE_NAMES),
|
|
254
|
-
});
|
|
255
|
-
fields.push('entry_type');
|
|
256
439
|
vectors.push(buildColumn(buildData({
|
|
257
|
-
type
|
|
440
|
+
type,
|
|
258
441
|
offset: 0,
|
|
259
442
|
length: totalRows,
|
|
260
443
|
nullCount: 0,
|
|
261
444
|
data: entryTypeIndices,
|
|
262
|
-
dictionary:
|
|
445
|
+
dictionary: entryTypeDictionary,
|
|
263
446
|
})));
|
|
264
447
|
}
|
|
265
448
|
/**
|
|
@@ -305,13 +488,14 @@ function buildPerBufferDictColumn(buffers, totalRows, fieldName, metadataGetter,
|
|
|
305
488
|
* Binary columns store arbitrary bytes (raw Uint8Array or encoder-encoded objects).
|
|
306
489
|
* At flush time, the encoder (if present) transforms stored values into Uint8Array.
|
|
307
490
|
*/
|
|
308
|
-
function buildBinaryColumnFromBuffers(buffers, columnName, totalRows, fieldSchema) {
|
|
491
|
+
function buildBinaryColumnFromBuffers(buffers, columnName, totalRows, fieldSchema, remaps) {
|
|
309
492
|
const encoder = getBinaryEncoder(fieldSchema);
|
|
310
493
|
// Collect all values from buffers, encode each if encoder is present
|
|
311
494
|
const allValues = [];
|
|
312
495
|
for (const buf of buffers) {
|
|
313
|
-
const col = getAllocatedBinaryColumn(buf, columnName);
|
|
314
|
-
const
|
|
496
|
+
const col = getAllocatedBinaryColumn(buf, columnName, remaps);
|
|
497
|
+
const sourceName = remaps ? resolveColumnName(buf, columnName, remaps) : columnName;
|
|
498
|
+
const srcNulls = buf.getNullsIfAllocated(sourceName);
|
|
315
499
|
for (let i = 0; i < buf._writeIndex; i++) {
|
|
316
500
|
if (srcNulls) {
|
|
317
501
|
const isValid = (srcNulls[i >>> 3] & (1 << (i & 7))) !== 0;
|
|
@@ -388,14 +572,14 @@ function buildBinaryColumnFromBuffers(buffers, columnName, totalRows, fieldSchem
|
|
|
388
572
|
* Dictionaries are built from the data in this batch only and are not shared
|
|
389
573
|
* with other batches, even when combined into a Table.
|
|
390
574
|
*/
|
|
391
|
-
export function convertToTable(buffer, systemColumnBuilder) {
|
|
575
|
+
export function convertToTable(buffer, systemColumnBuilder, borrowChunks = false) {
|
|
392
576
|
const buffers = [];
|
|
393
577
|
let currentBuffer = buffer;
|
|
394
578
|
while (currentBuffer) {
|
|
395
579
|
buffers.push(currentBuffer);
|
|
396
580
|
currentBuffer = currentBuffer._overflow;
|
|
397
581
|
}
|
|
398
|
-
return convertBuffersToTable(buffers, systemColumnBuilder);
|
|
582
|
+
return convertBuffersToTable(buffers, systemColumnBuilder, borrowChunks);
|
|
399
583
|
}
|
|
400
584
|
/**
|
|
401
585
|
* Convert multiple buffers to a single table.
|
|
@@ -404,13 +588,14 @@ export function convertToTable(buffer, systemColumnBuilder) {
|
|
|
404
588
|
* Dictionaries are built from the data in this batch only and are not shared
|
|
405
589
|
* with other batches, even when combined into a Table.
|
|
406
590
|
*/
|
|
407
|
-
function convertBuffersToTable(buffers, systemColumnBuilder) {
|
|
591
|
+
function convertBuffersToTable(buffers, systemColumnBuilder, borrowChunks = false) {
|
|
408
592
|
if (buffers.length === 0)
|
|
409
593
|
return tableFromColumns({});
|
|
410
594
|
const totalRows = buffers.reduce((sum, buf) => sum + buf._writeIndex, 0);
|
|
411
595
|
if (totalRows === 0)
|
|
412
596
|
return tableFromColumns({});
|
|
413
597
|
const schema = buffers[0]._logSchema;
|
|
598
|
+
const enumLookup = resolveEnumLookupDescriptor(schema);
|
|
414
599
|
// Build vectors first, then derive schema from them
|
|
415
600
|
// This ensures Field types and vector data types are identical (Arrow IPC requirement)
|
|
416
601
|
const fields = [];
|
|
@@ -421,46 +606,16 @@ function convertBuffersToTable(buffers, systemColumnBuilder) {
|
|
|
421
606
|
vectors.push(...systemColumns.vectors);
|
|
422
607
|
}
|
|
423
608
|
else {
|
|
424
|
-
|
|
425
|
-
const
|
|
609
|
+
const borrowEntryTypes = canBorrowEntryTypeChunks(buffers, borrowChunks);
|
|
610
|
+
const messageResult = buildMessageColumn(buffers, totalRows, undefined, !borrowEntryTypes);
|
|
611
|
+
// Build metadata columns - returns both fields and vectors with matching types.
|
|
612
|
+
const metadataResult = buildMetadataColumnsWithFields(buffers, totalRows, borrowChunks, messageResult.entryTypeIndices);
|
|
426
613
|
fields.push(...metadataResult.fields);
|
|
427
614
|
vectors.push(...metadataResult.vectors);
|
|
428
|
-
//
|
|
429
|
-
|
|
430
|
-
let { dictionary: dictValues, indices, arrowIndexType, nullBitmap, } = buildSortedCategoryDictionary(buffers, 'message', maskTransform);
|
|
431
|
-
// Ensure dictionary has at least one entry (empty string) if no messages were written
|
|
432
|
-
if (dictValues.length === 0) {
|
|
433
|
-
dictValues = [''];
|
|
434
|
-
}
|
|
435
|
-
// Ensure nullBitmap is all 1s (all valid) for eager column
|
|
436
|
-
if (!nullBitmap) {
|
|
437
|
-
const bitmapBytes = Math.ceil(totalRows / 8);
|
|
438
|
-
nullBitmap = new Uint8Array(bitmapBytes);
|
|
439
|
-
nullBitmap.fill(0xff);
|
|
440
|
-
}
|
|
441
|
-
// CRITICAL: Create ONE Dictionary type instance for field and batch data
|
|
442
|
-
// Arrow Schema validates that fields with same dictionary ID have identical type references
|
|
443
|
-
const messageDictType = dictionary(utf8(), arrowIndexType);
|
|
615
|
+
// Static vocabulary values form an immutable prefix. Only raw messages
|
|
616
|
+
// missing from that prefix are interned into a first-seen suffix.
|
|
444
617
|
fields.push('message');
|
|
445
|
-
|
|
446
|
-
const messageDictData = buildData({
|
|
447
|
-
type: utf8(),
|
|
448
|
-
offset: 0,
|
|
449
|
-
length: dictValues.length,
|
|
450
|
-
nullCount: 0,
|
|
451
|
-
valueOffsets: messageUtf8Offsets,
|
|
452
|
-
data: messageUtf8Data,
|
|
453
|
-
});
|
|
454
|
-
const messageData = buildData({
|
|
455
|
-
type: messageDictType,
|
|
456
|
-
offset: 0,
|
|
457
|
-
length: totalRows,
|
|
458
|
-
nullCount: 0, // message is eager, never null
|
|
459
|
-
data: indices,
|
|
460
|
-
nullBitmap, // Always include nullBitmap for message (even though nullCount is 0)
|
|
461
|
-
dictionary: buildColumn(messageDictData),
|
|
462
|
-
});
|
|
463
|
-
vectors.push(buildColumn(messageData));
|
|
618
|
+
vectors.push(messageResult.column);
|
|
464
619
|
}
|
|
465
620
|
// Build user attribute vectors
|
|
466
621
|
// Skip system schema fields - they are handled separately as system columns
|
|
@@ -471,17 +626,19 @@ function convertBuffersToTable(buffers, systemColumnBuilder) {
|
|
|
471
626
|
const arrowFieldName = getArrowFieldName(fieldName);
|
|
472
627
|
const columnName = fieldName; // User columns have no prefix
|
|
473
628
|
if (lmaoType === 'enum') {
|
|
474
|
-
const
|
|
629
|
+
const descriptor = enumLookup.byField[fieldName];
|
|
630
|
+
if (!descriptor)
|
|
631
|
+
throw new TypeError(`Enum lookup missing for field '${fieldName}'`);
|
|
632
|
+
const enumValues = descriptor.values;
|
|
475
633
|
const enumUtf8 = getEnumUtf8(fieldSchema);
|
|
476
|
-
|
|
477
|
-
const
|
|
478
|
-
const arrowIndexType = getArrowIndexTypeOr(fieldSchema, uint8());
|
|
634
|
+
const indexArrayCtor = descriptor.indexArrayConstructor;
|
|
635
|
+
const arrowIndexType = indexTypeForCount(enumValues.length);
|
|
479
636
|
// Collect value arrays - need to handle different TypedArray types
|
|
480
637
|
const valueArrays = [];
|
|
481
638
|
for (const buf of buffers) {
|
|
482
639
|
const column = buf.getColumnIfAllocated(columnName);
|
|
483
640
|
if (column && column instanceof indexArrayCtor) {
|
|
484
|
-
valueArrays.push(column.subarray(0, buf._writeIndex));
|
|
641
|
+
valueArrays.push(column.subarray(0, buf._writeIndex).slice());
|
|
485
642
|
}
|
|
486
643
|
else {
|
|
487
644
|
valueArrays.push(new indexArrayCtor(buf._writeIndex));
|
|
@@ -589,29 +746,46 @@ function convertBuffersToTable(buffers, systemColumnBuilder) {
|
|
|
589
746
|
}
|
|
590
747
|
}
|
|
591
748
|
else if (lmaoType === 'number') {
|
|
592
|
-
const valueArrays = [];
|
|
593
|
-
for (const buf of buffers) {
|
|
594
|
-
const column = buf.getColumnIfAllocated(columnName);
|
|
595
|
-
if (column && column instanceof Float64Array) {
|
|
596
|
-
valueArrays.push(column.subarray(0, buf._writeIndex));
|
|
597
|
-
}
|
|
598
|
-
else {
|
|
599
|
-
valueArrays.push(new F64Array(buf._writeIndex));
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
const allValues = concatenateFloat64Arrays(valueArrays);
|
|
603
|
-
const { nullBitmap, nullCount } = concatenateNullBitmaps(buffers, columnName);
|
|
604
749
|
const numberType = float64();
|
|
605
750
|
fields.push(arrowFieldName);
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
751
|
+
const borrowed = borrowChunks
|
|
752
|
+
? buffers.map((buffer) => {
|
|
753
|
+
const column = buffer.getColumnIfAllocated(columnName);
|
|
754
|
+
const validity = buffer.getNullsIfAllocated(columnName);
|
|
755
|
+
if (!(column instanceof Float64Array) || !(validity instanceof Uint8Array))
|
|
756
|
+
return undefined;
|
|
757
|
+
return buildColumn(buildData({
|
|
758
|
+
type: numberType,
|
|
759
|
+
offset: 0,
|
|
760
|
+
length: buffer._writeIndex,
|
|
761
|
+
nullCount: countNulls(validity, buffer._writeIndex),
|
|
762
|
+
data: column.subarray(0, buffer._writeIndex),
|
|
763
|
+
nullBitmap: validity.subarray(0, Math.ceil(buffer._writeIndex / 8)),
|
|
764
|
+
}));
|
|
765
|
+
})
|
|
766
|
+
: undefined;
|
|
767
|
+
if (borrowed?.every((chunk) => chunk !== undefined)) {
|
|
768
|
+
vectors.push(combineColumnChunks(borrowed));
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
const valueArrays = [];
|
|
772
|
+
for (const buffer of buffers) {
|
|
773
|
+
const column = buffer.getColumnIfAllocated(columnName);
|
|
774
|
+
valueArrays.push(column instanceof Float64Array
|
|
775
|
+
? column.subarray(0, buffer._writeIndex).slice()
|
|
776
|
+
: new F64Array(buffer._writeIndex));
|
|
777
|
+
}
|
|
778
|
+
const allValues = concatenateFloat64Arrays(valueArrays);
|
|
779
|
+
const { nullBitmap, nullCount } = concatenateNullBitmaps(buffers, columnName);
|
|
780
|
+
vectors.push(buildColumn(buildData({
|
|
781
|
+
type: numberType,
|
|
782
|
+
offset: 0,
|
|
783
|
+
length: totalRows,
|
|
784
|
+
nullCount,
|
|
785
|
+
data: allValues,
|
|
786
|
+
nullBitmap,
|
|
787
|
+
})));
|
|
788
|
+
}
|
|
615
789
|
}
|
|
616
790
|
else if (lmaoType === 'boolean') {
|
|
617
791
|
const valueArrays = [];
|
|
@@ -619,7 +793,7 @@ function convertBuffersToTable(buffers, systemColumnBuilder) {
|
|
|
619
793
|
const column = buf.getColumnIfAllocated(columnName);
|
|
620
794
|
if (column && column instanceof Uint8Array) {
|
|
621
795
|
const requiredBytes = Math.ceil(buf._writeIndex / 8);
|
|
622
|
-
valueArrays.push(column.subarray(0, requiredBytes));
|
|
796
|
+
valueArrays.push(column.subarray(0, requiredBytes).slice());
|
|
623
797
|
}
|
|
624
798
|
else {
|
|
625
799
|
const requiredBytes = Math.ceil(buf._writeIndex / 8);
|
|
@@ -655,13 +829,13 @@ function convertBuffersToTable(buffers, systemColumnBuilder) {
|
|
|
655
829
|
* This is required for Arrow IPC serialization - Schema validates that
|
|
656
830
|
* fields with same dictionary ID have identical type object references.
|
|
657
831
|
*/
|
|
658
|
-
function buildMetadataColumnsWithFields(buffers, totalRows) {
|
|
832
|
+
function buildMetadataColumnsWithFields(buffers, totalRows, borrowChunks = false, classifiedEntryTypes) {
|
|
659
833
|
const fields = [];
|
|
660
834
|
const vectors = [];
|
|
661
835
|
// Column order: timestamp, trace_id, thread_id, span_id, parent_thread_id, parent_span_id,
|
|
662
836
|
// entry_type, package_name, package_file, git_sha
|
|
663
837
|
// 1. Timestamp
|
|
664
|
-
buildTimestampColumn(buffers, totalRows, fields, vectors);
|
|
838
|
+
buildTimestampColumn(buffers, totalRows, fields, vectors, borrowChunks);
|
|
665
839
|
// 2. Trace ID dictionary (built inline from buffers)
|
|
666
840
|
const traceIdSet = new Set();
|
|
667
841
|
for (const buf of buffers)
|
|
@@ -700,7 +874,7 @@ function buildMetadataColumnsWithFields(buffers, totalRows) {
|
|
|
700
874
|
// 3-6. thread_id, span_id, parent_thread_id, parent_span_id
|
|
701
875
|
buildNonDictIdentityColumns(buffers, totalRows, fields, vectors);
|
|
702
876
|
// 7. Entry type
|
|
703
|
-
buildEntryTypeColumn(buffers, totalRows, fields, vectors);
|
|
877
|
+
buildEntryTypeColumn(buffers, totalRows, fields, vectors, undefined, borrowChunks, classifiedEntryTypes);
|
|
704
878
|
// 8-10. Per-buffer metadata columns (package_name, package_file, git_sha)
|
|
705
879
|
for (const [fieldName, metadataGetter] of [
|
|
706
880
|
['package_name', (m) => m.package_name],
|
|
@@ -721,6 +895,43 @@ function buildMetadataColumnsWithFields(buffers, totalRows) {
|
|
|
721
895
|
}
|
|
722
896
|
return { fields, vectors };
|
|
723
897
|
}
|
|
898
|
+
function isEpochPinnableBuffer(buffer) {
|
|
899
|
+
if (!('_allocator' in buffer))
|
|
900
|
+
return false;
|
|
901
|
+
const allocator = Reflect.get(buffer, '_allocator');
|
|
902
|
+
return (typeof allocator === 'object' &&
|
|
903
|
+
allocator !== null &&
|
|
904
|
+
typeof Reflect.get(allocator, 'pinMemoryEpoch') === 'function');
|
|
905
|
+
}
|
|
906
|
+
function createLeasedConversion(root, buffers, build) {
|
|
907
|
+
const topology = root._traceRoot._topology;
|
|
908
|
+
topology.assertLive(root);
|
|
909
|
+
const releaseTopology = topology.acquireLease();
|
|
910
|
+
const generations = new Set();
|
|
911
|
+
const allocators = new Set();
|
|
912
|
+
for (const buffer of buffers) {
|
|
913
|
+
generations.add(buffer._vocabularyGeneration);
|
|
914
|
+
if (isEpochPinnableBuffer(buffer))
|
|
915
|
+
allocators.add(buffer._allocator);
|
|
916
|
+
}
|
|
917
|
+
const epochPins = Array.from(allocators, (allocator) => allocator.pinMemoryEpoch());
|
|
918
|
+
// WASM linear-memory growth cannot preserve borrowed JS TypedArray views, so
|
|
919
|
+
// its leased result uses the existing Arrow-owned copy path. JS heap buffers
|
|
920
|
+
// expose their physical chunks directly under the topology lease.
|
|
921
|
+
const borrowChunks = epochPins.length === 0;
|
|
922
|
+
try {
|
|
923
|
+
const table = build(borrowChunks);
|
|
924
|
+
for (const pin of epochPins)
|
|
925
|
+
pin.release();
|
|
926
|
+
return createArrowLease(table, [...buffers, ...generations], [releaseTopology]);
|
|
927
|
+
}
|
|
928
|
+
catch (error) {
|
|
929
|
+
for (const pin of epochPins)
|
|
930
|
+
pin.release();
|
|
931
|
+
releaseTopology();
|
|
932
|
+
throw error;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
724
935
|
/**
|
|
725
936
|
* Convert SpanBuffer (and its overflow chain) to Arrow Table
|
|
726
937
|
*/
|
|
@@ -730,6 +941,19 @@ export function convertToArrowTable(buffer, systemColumnBuilder) {
|
|
|
730
941
|
return tableFromColumns({});
|
|
731
942
|
return batch;
|
|
732
943
|
}
|
|
944
|
+
/** Borrow JS physical Arrow chunks until the returned lease is released. */
|
|
945
|
+
export function convertToLeasedArrowTable(buffer, systemColumnBuilder) {
|
|
946
|
+
const buffers = [];
|
|
947
|
+
let segment = buffer;
|
|
948
|
+
while (segment) {
|
|
949
|
+
buffers.push(segment);
|
|
950
|
+
segment = segment._overflow;
|
|
951
|
+
}
|
|
952
|
+
return createLeasedConversion(buffer, buffers, (borrowChunks) => {
|
|
953
|
+
const table = convertToTable(buffer, systemColumnBuilder, borrowChunks);
|
|
954
|
+
return table.numRows === 0 ? tableFromColumns({}) : table;
|
|
955
|
+
});
|
|
956
|
+
}
|
|
733
957
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
734
958
|
// Tree Conversion with Shared Dictionaries
|
|
735
959
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -740,25 +964,35 @@ export function convertToArrowTable(buffer, systemColumnBuilder) {
|
|
|
740
964
|
* - Pass 1: Walk tree, build dictionaries (collect unique strings, cache UTF-8)
|
|
741
965
|
* - Pass 2: Walk tree, convert each buffer to a table using shared dictionaries
|
|
742
966
|
*/
|
|
743
|
-
export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, modulesToLogStats, periodStartNs) {
|
|
967
|
+
export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, modulesToLogStats, periodStartNs, borrowChunks = false) {
|
|
744
968
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
745
969
|
// PASS 0: Collect ALL unique schema fields from ALL buffers in the tree
|
|
746
970
|
// Per specs/lmao/01k_tree_walker_and_arrow_conversion.md - child spans may have different schemas
|
|
747
971
|
// (e.g., library prefixed schemas like db_query, http_status, etc.)
|
|
748
972
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
749
973
|
const mergedSchemaFields = new Map();
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
974
|
+
const remaps = new WeakMap();
|
|
975
|
+
const enumLookupsByField = new Map();
|
|
976
|
+
walkSpanTree(rootBuffer, (buffer, remapDescriptor) => {
|
|
977
|
+
const enumLookup = resolveEnumLookupDescriptor(buffer._logSchema);
|
|
978
|
+
if (remapDescriptor) {
|
|
979
|
+
remaps.set(buffer, remapDescriptor);
|
|
980
|
+
for (const [fieldName, sourceName, fieldSchema] of remapDescriptor.columns) {
|
|
981
|
+
if (!SYSTEM_SCHEMA_FIELD_NAMES.has(fieldName) && !mergedSchemaFields.has(fieldName)) {
|
|
982
|
+
mergedSchemaFields.set(fieldName, fieldSchema);
|
|
983
|
+
const descriptor = enumLookup.byField[sourceName];
|
|
984
|
+
if (descriptor)
|
|
985
|
+
enumLookupsByField.set(fieldName, descriptor);
|
|
986
|
+
}
|
|
758
987
|
}
|
|
759
|
-
|
|
760
|
-
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
for (const [fieldName, fieldSchema] of buffer._columns) {
|
|
991
|
+
if (!SYSTEM_SCHEMA_FIELD_NAMES.has(fieldName) && !mergedSchemaFields.has(fieldName)) {
|
|
761
992
|
mergedSchemaFields.set(fieldName, fieldSchema);
|
|
993
|
+
const descriptor = enumLookup.byField[fieldName];
|
|
994
|
+
if (descriptor)
|
|
995
|
+
enumLookupsByField.set(fieldName, descriptor);
|
|
762
996
|
}
|
|
763
997
|
}
|
|
764
998
|
});
|
|
@@ -790,11 +1024,6 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
790
1024
|
textOriginalToMasked.set(fieldName, new Map());
|
|
791
1025
|
}
|
|
792
1026
|
}
|
|
793
|
-
// System attribute column: message (eager category, not in user schema)
|
|
794
|
-
// message is always present (eager allocation), so we need to handle it explicitly
|
|
795
|
-
categoryBuilders.set('message', new DictBuilder(globalUtf8Cache));
|
|
796
|
-
categoryMaskTransforms.set('message', undefined); // message has no masking
|
|
797
|
-
categoryOriginalToMasked.set('message', new Map());
|
|
798
1027
|
// Metadata column dictionaries
|
|
799
1028
|
// For traceId (metadata), use DictionaryBuilder (values not pre-encoded)
|
|
800
1029
|
const traceIdBuilder = new DictBuilder(globalUtf8Cache);
|
|
@@ -812,12 +1041,12 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
812
1041
|
uniqueModules.add(buffer._callsiteMetadata);
|
|
813
1042
|
}
|
|
814
1043
|
for (const [fieldName, builder] of categoryBuilders) {
|
|
815
|
-
const col = getAllocatedStringColumn(buffer, fieldName);
|
|
816
1044
|
const maskTransform = categoryMaskTransforms.get(fieldName);
|
|
817
1045
|
const originalToMasked = categoryOriginalToMasked.get(fieldName);
|
|
818
1046
|
if (!originalToMasked) {
|
|
819
1047
|
throw new Error(`Category originalToMasked map not found for field: ${fieldName}`);
|
|
820
1048
|
}
|
|
1049
|
+
const col = getAllocatedStringColumn(buffer, fieldName, remaps);
|
|
821
1050
|
if (col) {
|
|
822
1051
|
for (let i = 0; i < buffer._writeIndex; i++) {
|
|
823
1052
|
const originalValue = col[i];
|
|
@@ -833,7 +1062,7 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
833
1062
|
}
|
|
834
1063
|
// Also add scope values to dictionary (they may not be in columns)
|
|
835
1064
|
// Per specs/lmao/01i_span_scope_attributes.md: scope values fill NULL cells at Arrow conversion
|
|
836
|
-
const scopeValue = getStringScopeValue(buffer, fieldName);
|
|
1065
|
+
const scopeValue = getStringScopeValue(buffer, fieldName, remaps);
|
|
837
1066
|
if (scopeValue !== undefined) {
|
|
838
1067
|
let maskedScopeValue = originalToMasked.get(scopeValue);
|
|
839
1068
|
if (maskedScopeValue === undefined) {
|
|
@@ -844,7 +1073,7 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
844
1073
|
}
|
|
845
1074
|
}
|
|
846
1075
|
for (const [fieldName, builder] of textBuilders) {
|
|
847
|
-
const col = getAllocatedStringColumn(buffer, fieldName);
|
|
1076
|
+
const col = getAllocatedStringColumn(buffer, fieldName, remaps);
|
|
848
1077
|
const maskTransform = textMaskTransforms.get(fieldName);
|
|
849
1078
|
const originalToMasked = textOriginalToMasked.get(fieldName);
|
|
850
1079
|
if (!originalToMasked) {
|
|
@@ -865,7 +1094,7 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
865
1094
|
}
|
|
866
1095
|
// Also add scope values to dictionary (they may not be in columns)
|
|
867
1096
|
// Per specs/lmao/01i_span_scope_attributes.md: scope values fill NULL cells at Arrow conversion
|
|
868
|
-
const scopeValue = getStringScopeValue(buffer, fieldName);
|
|
1097
|
+
const scopeValue = getStringScopeValue(buffer, fieldName, remaps);
|
|
869
1098
|
if (scopeValue !== undefined) {
|
|
870
1099
|
let maskedScopeValue = originalToMasked.get(scopeValue);
|
|
871
1100
|
if (maskedScopeValue === undefined) {
|
|
@@ -909,14 +1138,6 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
909
1138
|
for (const [name, builder] of textBuilders) {
|
|
910
1139
|
textDicts.set(name, builder.finalize(false)); // not sorted
|
|
911
1140
|
}
|
|
912
|
-
// Get messageDict from categoryDicts (message is handled as a category column)
|
|
913
|
-
// If no messages were written, create an empty dictionary
|
|
914
|
-
let messageDict = categoryDicts.get('message');
|
|
915
|
-
if (!messageDict) {
|
|
916
|
-
const messageBuilder = new DictBuilder(globalUtf8Cache);
|
|
917
|
-
messageBuilder.add(''); // Single empty string entry
|
|
918
|
-
messageDict = messageBuilder.finalize(true); // sorted
|
|
919
|
-
}
|
|
920
1141
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
921
1142
|
// PASS 2: Collect all buffers with non-zero rows
|
|
922
1143
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -928,7 +1149,7 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
928
1149
|
});
|
|
929
1150
|
// Build a single table from all buffers
|
|
930
1151
|
const batch = allBuffers.length > 0
|
|
931
|
-
? convertBuffersWithSharedDicts(allBuffers, traceIdDict, packageDict, packagePathDict, gitShaDict, categoryDicts, textDicts, schemaFields, categoryOriginalToMasked, textOriginalToMasked)
|
|
1152
|
+
? convertBuffersWithSharedDicts(allBuffers, traceIdDict, packageDict, packagePathDict, gitShaDict, categoryDicts, textDicts, schemaFields, enumLookupsByField, categoryOriginalToMasked, textOriginalToMasked, remaps, borrowChunks)
|
|
932
1153
|
: undefined;
|
|
933
1154
|
// Create capacity stats table if needed
|
|
934
1155
|
if (modulesToLogStats && modulesToLogStats.length > 0) {
|
|
@@ -946,6 +1167,15 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
946
1167
|
}
|
|
947
1168
|
return tableFromColumns({});
|
|
948
1169
|
}
|
|
1170
|
+
/** Convert a logical trace tree while pinning every borrowed physical chunk. */
|
|
1171
|
+
export function convertSpanTreeToLeasedArrowTable(rootBuffer, systemColumnBuilder, modulesToLogStats, periodStartNs) {
|
|
1172
|
+
const buffers = [];
|
|
1173
|
+
walkSpanTree(rootBuffer, (buffer) => {
|
|
1174
|
+
if (buffer._writeIndex > 0)
|
|
1175
|
+
buffers.push(buffer);
|
|
1176
|
+
});
|
|
1177
|
+
return createLeasedConversion(rootBuffer, buffers, (borrowChunks) => convertSpanTreeToArrowTable(rootBuffer, systemColumnBuilder, modulesToLogStats, periodStartNs, borrowChunks));
|
|
1178
|
+
}
|
|
949
1179
|
/**
|
|
950
1180
|
* Convert multiple buffers to a single table using pre-built dictionaries.
|
|
951
1181
|
*
|
|
@@ -954,10 +1184,12 @@ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, mo
|
|
|
954
1184
|
* a single table. The resulting batches contain their own dictionary data and
|
|
955
1185
|
* are not shared with other batches, even when combined into a Table.
|
|
956
1186
|
*/
|
|
957
|
-
function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packagePathDict, gitShaDict, categoryDicts, textDicts, schemaFields, categoryOriginalToMasked, textOriginalToMasked) {
|
|
1187
|
+
function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packagePathDict, gitShaDict, categoryDicts, textDicts, schemaFields, enumLookupsByField, categoryOriginalToMasked, textOriginalToMasked, remaps, borrowChunks = false) {
|
|
958
1188
|
const totalRows = buffers.reduce((sum, buf) => sum + buf._writeIndex, 0);
|
|
959
1189
|
const fields = [];
|
|
960
1190
|
const vectors = [];
|
|
1191
|
+
const borrowEntryTypes = canBorrowEntryTypeChunks(buffers, borrowChunks);
|
|
1192
|
+
const messageResult = buildMessageColumn(buffers, totalRows, 5, !borrowEntryTypes);
|
|
961
1193
|
// Dictionary types with explicit IDs for IPC serialization
|
|
962
1194
|
const traceIdType = dictionary(utf8(), traceIdDict.arrowIndexType, false, 0);
|
|
963
1195
|
const entryTypeDictType = dictionary(utf8(), int8(), false, 1);
|
|
@@ -967,7 +1199,7 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
967
1199
|
// Column order: timestamp, trace_id, thread_id, span_id, parent_thread_id, parent_span_id,
|
|
968
1200
|
// entry_type, package_name, package_file, git_sha
|
|
969
1201
|
// 1. Timestamp
|
|
970
|
-
buildTimestampColumn(buffers, totalRows, fields, vectors);
|
|
1202
|
+
buildTimestampColumn(buffers, totalRows, fields, vectors, borrowChunks);
|
|
971
1203
|
// 2. Trace ID (using shared pre-built dictionary)
|
|
972
1204
|
const traceIdIndices = new traceIdDict.indexArrayCtor(totalRows);
|
|
973
1205
|
let offset = 0;
|
|
@@ -995,7 +1227,7 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
995
1227
|
// 3-6. thread_id, span_id, parent_thread_id, parent_span_id
|
|
996
1228
|
buildNonDictIdentityColumns(buffers, totalRows, fields, vectors);
|
|
997
1229
|
// 7. Entry type (with explicit dictionary ID for IPC)
|
|
998
|
-
buildEntryTypeColumn(buffers, totalRows, fields, vectors, entryTypeDictType);
|
|
1230
|
+
buildEntryTypeColumn(buffers, totalRows, fields, vectors, entryTypeDictType, borrowChunks, messageResult.entryTypeIndices);
|
|
999
1231
|
// 8-10. Per-buffer metadata columns using shared pre-built dictionaries
|
|
1000
1232
|
// Per specs/lmao/01c_context_flow_and_op_wrappers.md:
|
|
1001
1233
|
// - Row 0 (span-start): uses callsiteModule for gitSha/packageName/packagePath
|
|
@@ -1012,46 +1244,7 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
1012
1244
|
// System attribute and user attribute columns - concatenate from all buffers
|
|
1013
1245
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1014
1246
|
// System attribute column: message (at fixed position 10, before user attributes)
|
|
1015
|
-
|
|
1016
|
-
const messageOriginalToMasked = categoryOriginalToMasked.get('message');
|
|
1017
|
-
if (!messageDict || !messageOriginalToMasked) {
|
|
1018
|
-
throw new Error('Message dictionary or mapping not found');
|
|
1019
|
-
}
|
|
1020
|
-
const messageFieldType = dictionary(utf8(), messageDict.arrowIndexType, false, 5);
|
|
1021
|
-
const messageIndices = new messageDict.indexArrayCtor(totalRows);
|
|
1022
|
-
const messageNullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
|
|
1023
|
-
let messageRowOffset = 0;
|
|
1024
|
-
for (const buf of buffers) {
|
|
1025
|
-
const col = getAllocatedStringColumn(buf, 'message');
|
|
1026
|
-
if (col) {
|
|
1027
|
-
for (let i = 0; i < buf._writeIndex; i++) {
|
|
1028
|
-
const v = col[i];
|
|
1029
|
-
const rowIdx = messageRowOffset + i;
|
|
1030
|
-
if (v != null) {
|
|
1031
|
-
const maskedValue = messageOriginalToMasked.get(v) ?? v;
|
|
1032
|
-
messageIndices[rowIdx] = messageDict.indexMap.get(maskedValue) ?? 0;
|
|
1033
|
-
messageNullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
messageRowOffset += buf._writeIndex;
|
|
1038
|
-
}
|
|
1039
|
-
vectors.push(buildColumn(buildData({
|
|
1040
|
-
type: messageFieldType,
|
|
1041
|
-
offset: 0,
|
|
1042
|
-
length: totalRows,
|
|
1043
|
-
nullCount: 0, // message is eager, never null
|
|
1044
|
-
data: messageIndices,
|
|
1045
|
-
nullBitmap: messageNullBitmap,
|
|
1046
|
-
dictionary: buildColumn(buildData({
|
|
1047
|
-
type: utf8(),
|
|
1048
|
-
offset: 0,
|
|
1049
|
-
length: messageDict.indexMap.size,
|
|
1050
|
-
nullCount: 0,
|
|
1051
|
-
valueOffsets: messageDict.offsets,
|
|
1052
|
-
data: messageDict.data,
|
|
1053
|
-
})),
|
|
1054
|
-
})));
|
|
1247
|
+
vectors.push(messageResult.column);
|
|
1055
1248
|
fields.push('message');
|
|
1056
1249
|
// System attribute column: uint64_value (for buffer metrics - op durations, counts, etc.)
|
|
1057
1250
|
// For span data, this is all null - only buffer metrics use it
|
|
@@ -1082,9 +1275,9 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
1082
1275
|
let rowOffset = 0;
|
|
1083
1276
|
// Per specs/lmao/01i_span_scope_attributes.md: scope values fill NULL cells at Arrow conversion
|
|
1084
1277
|
for (const buf of buffers) {
|
|
1085
|
-
const col = getAllocatedStringColumn(buf, columnName);
|
|
1278
|
+
const col = getAllocatedStringColumn(buf, columnName, remaps);
|
|
1086
1279
|
// Check if this buffer has a scope value for this field
|
|
1087
|
-
const scopeValue = getStringScopeValue(buf, fieldName);
|
|
1280
|
+
const scopeValue = getStringScopeValue(buf, fieldName, remaps);
|
|
1088
1281
|
let scopeEncodedValue;
|
|
1089
1282
|
if (scopeValue !== undefined) {
|
|
1090
1283
|
const maskedScopeValue = originalToMasked.get(scopeValue) ?? scopeValue;
|
|
@@ -1153,9 +1346,9 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
1153
1346
|
let nullCount = 0;
|
|
1154
1347
|
let rowOffset = 0;
|
|
1155
1348
|
for (const buf of buffers) {
|
|
1156
|
-
const col = getAllocatedStringColumn(buf, columnName);
|
|
1349
|
+
const col = getAllocatedStringColumn(buf, columnName, remaps);
|
|
1157
1350
|
// Check if this buffer has a scope value for this field
|
|
1158
|
-
const scopeValue = getStringScopeValue(buf, fieldName);
|
|
1351
|
+
const scopeValue = getStringScopeValue(buf, fieldName, remaps);
|
|
1159
1352
|
let scopeEncodedValue;
|
|
1160
1353
|
if (scopeValue !== undefined) {
|
|
1161
1354
|
const maskedScopeValue = originalToMasked.get(scopeValue) ?? scopeValue;
|
|
@@ -1214,76 +1407,101 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
1214
1407
|
fields.push(arrowFieldName);
|
|
1215
1408
|
}
|
|
1216
1409
|
else if (lmaoType === 'number') {
|
|
1217
|
-
const
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1410
|
+
const borrowed = borrowChunks
|
|
1411
|
+
? buffers.map((buffer) => {
|
|
1412
|
+
const sourceName = resolveColumnName(buffer, columnName, remaps);
|
|
1413
|
+
if (getNumberScopeValue(buffer, fieldName, remaps) !== undefined)
|
|
1414
|
+
return undefined;
|
|
1415
|
+
const column = buffer.getColumnIfAllocated(sourceName);
|
|
1416
|
+
const validity = buffer.getNullsIfAllocated(sourceName);
|
|
1417
|
+
if (!(column instanceof Float64Array) || !(validity instanceof Uint8Array))
|
|
1418
|
+
return undefined;
|
|
1419
|
+
return buildColumn(buildData({
|
|
1420
|
+
type: float64(),
|
|
1421
|
+
offset: 0,
|
|
1422
|
+
length: buffer._writeIndex,
|
|
1423
|
+
nullCount: countNulls(validity, buffer._writeIndex),
|
|
1424
|
+
data: column.subarray(0, buffer._writeIndex),
|
|
1425
|
+
nullBitmap: validity.subarray(0, Math.ceil(buffer._writeIndex / 8)),
|
|
1426
|
+
}));
|
|
1427
|
+
})
|
|
1428
|
+
: undefined;
|
|
1429
|
+
if (borrowed?.every((chunk) => chunk !== undefined)) {
|
|
1430
|
+
vectors.push(combineColumnChunks(borrowed));
|
|
1431
|
+
}
|
|
1432
|
+
else {
|
|
1433
|
+
const allValues = new F64Array(totalRows);
|
|
1434
|
+
const nullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
|
|
1435
|
+
// Start with all nulls (bits cleared) - we'll set bits as we find values
|
|
1436
|
+
let nullCount = 0;
|
|
1437
|
+
let rowOffset = 0;
|
|
1438
|
+
for (const buf of buffers) {
|
|
1439
|
+
const sourceName = resolveColumnName(buf, columnName, remaps);
|
|
1440
|
+
const col = buf.getColumnIfAllocated(sourceName);
|
|
1441
|
+
const srcNulls = buf.getNullsIfAllocated(sourceName);
|
|
1442
|
+
// Check if this buffer has a scope value for this field
|
|
1443
|
+
const scopeValue = getNumberScopeValue(buf, fieldName, remaps);
|
|
1444
|
+
if (col instanceof Float64Array) {
|
|
1445
|
+
allValues.set(col.subarray(0, buf._writeIndex), rowOffset);
|
|
1446
|
+
if (srcNulls) {
|
|
1447
|
+
// Process each row - direct write wins, then scope, then null
|
|
1448
|
+
for (let i = 0; i < buf._writeIndex; i++) {
|
|
1449
|
+
const srcByte = i >>> 3;
|
|
1450
|
+
const srcBit = i & 7;
|
|
1451
|
+
const isValid = (srcNulls[srcByte] & (1 << srcBit)) !== 0;
|
|
1452
|
+
const rowIdx = rowOffset + i;
|
|
1453
|
+
if (isValid) {
|
|
1454
|
+
// Direct write - mark as valid
|
|
1455
|
+
nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
|
|
1456
|
+
}
|
|
1457
|
+
else if (scopeValue !== undefined) {
|
|
1458
|
+
// No direct write, but have scope value - use it
|
|
1459
|
+
allValues[rowIdx] = scopeValue;
|
|
1460
|
+
nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
|
|
1461
|
+
}
|
|
1462
|
+
else {
|
|
1463
|
+
// No direct write and no scope - null
|
|
1464
|
+
nullCount++;
|
|
1465
|
+
}
|
|
1244
1466
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1467
|
+
}
|
|
1468
|
+
else {
|
|
1469
|
+
// No null bitmap means column was allocated but no writes - check scope
|
|
1470
|
+
for (let i = 0; i < buf._writeIndex; i++) {
|
|
1471
|
+
const rowIdx = rowOffset + i;
|
|
1472
|
+
if (scopeValue !== undefined) {
|
|
1473
|
+
allValues[rowIdx] = scopeValue;
|
|
1474
|
+
nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
|
|
1475
|
+
}
|
|
1476
|
+
else {
|
|
1477
|
+
nullCount++;
|
|
1478
|
+
}
|
|
1248
1479
|
}
|
|
1249
1480
|
}
|
|
1250
1481
|
}
|
|
1251
|
-
else {
|
|
1252
|
-
//
|
|
1482
|
+
else if (scopeValue !== undefined) {
|
|
1483
|
+
// Column not allocated but we have scope - fill all rows with scope value
|
|
1253
1484
|
for (let i = 0; i < buf._writeIndex; i++) {
|
|
1254
1485
|
const rowIdx = rowOffset + i;
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
|
|
1258
|
-
}
|
|
1259
|
-
else {
|
|
1260
|
-
nullCount++;
|
|
1261
|
-
}
|
|
1486
|
+
allValues[rowIdx] = scopeValue;
|
|
1487
|
+
nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
|
|
1262
1488
|
}
|
|
1263
1489
|
}
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
for (let i = 0; i < buf._writeIndex; i++) {
|
|
1268
|
-
const rowIdx = rowOffset + i;
|
|
1269
|
-
allValues[rowIdx] = scopeValue;
|
|
1270
|
-
nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
|
|
1490
|
+
else {
|
|
1491
|
+
// Column doesn't exist for this buffer and no scope - all nulls
|
|
1492
|
+
nullCount += buf._writeIndex;
|
|
1271
1493
|
}
|
|
1494
|
+
rowOffset += buf._writeIndex;
|
|
1272
1495
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1496
|
+
vectors.push(buildColumn(buildData({
|
|
1497
|
+
type: float64(),
|
|
1498
|
+
offset: 0,
|
|
1499
|
+
length: totalRows,
|
|
1500
|
+
nullCount,
|
|
1501
|
+
data: allValues,
|
|
1502
|
+
nullBitmap: nullCount > 0 ? nullBitmap : undefined,
|
|
1503
|
+
})));
|
|
1278
1504
|
}
|
|
1279
|
-
vectors.push(buildColumn(buildData({
|
|
1280
|
-
type: float64(),
|
|
1281
|
-
offset: 0,
|
|
1282
|
-
length: totalRows,
|
|
1283
|
-
nullCount,
|
|
1284
|
-
data: allValues,
|
|
1285
|
-
nullBitmap: nullCount > 0 ? nullBitmap : undefined,
|
|
1286
|
-
})));
|
|
1287
1505
|
fields.push(arrowFieldName);
|
|
1288
1506
|
}
|
|
1289
1507
|
else if (lmaoType === 'boolean') {
|
|
@@ -1294,10 +1512,11 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
1294
1512
|
let nullCount = 0;
|
|
1295
1513
|
let rowOffset = 0;
|
|
1296
1514
|
for (const buf of buffers) {
|
|
1297
|
-
const
|
|
1298
|
-
const
|
|
1515
|
+
const sourceName = resolveColumnName(buf, columnName, remaps);
|
|
1516
|
+
const col = buf.getColumnIfAllocated(sourceName);
|
|
1517
|
+
const srcNulls = buf.getNullsIfAllocated(sourceName);
|
|
1299
1518
|
// Check if this buffer has a scope value for this field
|
|
1300
|
-
const scopeValue = getBooleanScopeValue(buf, fieldName);
|
|
1519
|
+
const scopeValue = getBooleanScopeValue(buf, fieldName, remaps);
|
|
1301
1520
|
if (col instanceof Uint8Array) {
|
|
1302
1521
|
// Copy boolean values bit by bit - can't avoid loop for bit-level operations
|
|
1303
1522
|
for (let i = 0; i < buf._writeIndex; i++) {
|
|
@@ -1367,30 +1586,25 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
1367
1586
|
fields.push(arrowFieldName);
|
|
1368
1587
|
}
|
|
1369
1588
|
else if (lmaoType === 'enum') {
|
|
1370
|
-
const
|
|
1589
|
+
const descriptor = enumLookupsByField.get(fieldName);
|
|
1590
|
+
if (!descriptor)
|
|
1591
|
+
throw new TypeError(`Enum lookup missing for field '${fieldName}'`);
|
|
1592
|
+
const enumValues = descriptor.values;
|
|
1371
1593
|
const enumUtf8 = getEnumUtf8(fieldSchema);
|
|
1372
|
-
|
|
1373
|
-
const
|
|
1374
|
-
const arrowIndexType = getArrowIndexTypeOr(fieldSchema, uint8());
|
|
1594
|
+
const indexArrayCtor = descriptor.indexArrayConstructor;
|
|
1595
|
+
const arrowIndexType = indexTypeForCount(enumValues.length);
|
|
1375
1596
|
const allIndices = new indexArrayCtor(totalRows);
|
|
1376
1597
|
const nullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
|
|
1377
1598
|
// Start with all nulls (bits cleared) - we'll set bits as we find values
|
|
1378
1599
|
let nullCount = 0;
|
|
1379
1600
|
let rowOffset = 0;
|
|
1380
|
-
// Build enum value to index mapping for scope lookup
|
|
1381
|
-
const enumValueToIndex = new Map();
|
|
1382
|
-
for (let i = 0; i < enumValues.length; i++) {
|
|
1383
|
-
enumValueToIndex.set(enumValues[i], i);
|
|
1384
|
-
}
|
|
1385
1601
|
for (const buf of buffers) {
|
|
1386
|
-
const
|
|
1387
|
-
const
|
|
1602
|
+
const sourceName = resolveColumnName(buf, columnName, remaps);
|
|
1603
|
+
const col = buf.getColumnIfAllocated(sourceName);
|
|
1604
|
+
const srcNulls = buf.getNullsIfAllocated(sourceName);
|
|
1388
1605
|
// Check if this buffer has a scope value for this field
|
|
1389
|
-
const scopeValue = getStringScopeValue(buf, fieldName);
|
|
1390
|
-
|
|
1391
|
-
if (scopeValue !== undefined) {
|
|
1392
|
-
scopeEncodedValue = enumValueToIndex.get(scopeValue);
|
|
1393
|
-
}
|
|
1606
|
+
const scopeValue = getStringScopeValue(buf, fieldName, remaps);
|
|
1607
|
+
const scopeEncodedValue = scopeValue === undefined ? undefined : descriptor.encode(scopeValue);
|
|
1394
1608
|
if (col instanceof indexArrayCtor) {
|
|
1395
1609
|
allIndices.set(col.subarray(0, buf._writeIndex), rowOffset);
|
|
1396
1610
|
if (srcNulls) {
|
|
@@ -1464,7 +1678,7 @@ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packag
|
|
|
1464
1678
|
else if (lmaoType === 'binary') {
|
|
1465
1679
|
// Binary columns: raw Uint8Array or encoder-wrapped values (e.g. msgpack)
|
|
1466
1680
|
// Binary columns don't use dictionaries and are not scope-fillable
|
|
1467
|
-
const { column } = buildBinaryColumnFromBuffers(buffers, columnName, totalRows, fieldSchema);
|
|
1681
|
+
const { column } = buildBinaryColumnFromBuffers(buffers, columnName, totalRows, fieldSchema, remaps);
|
|
1468
1682
|
fields.push(arrowFieldName);
|
|
1469
1683
|
vectors.push(column);
|
|
1470
1684
|
}
|