@smoothbricks/lmao 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/README.md +206 -206
  2. package/dist/allocator.wasm +0 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -0
  6. package/dist/lib/JsBufferStrategy.d.ts +4 -3
  7. package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
  8. package/dist/lib/JsBufferStrategy.js +18 -11
  9. package/dist/lib/arrow/lease.d.ts +10 -0
  10. package/dist/lib/arrow/lease.d.ts.map +1 -0
  11. package/dist/lib/arrow/lease.js +33 -0
  12. package/dist/lib/arrow/utils.d.ts +3 -4
  13. package/dist/lib/arrow/utils.d.ts.map +1 -1
  14. package/dist/lib/arrow/utils.js +12 -13
  15. package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
  16. package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
  17. package/dist/lib/arrow/vocabularyDictionary.js +95 -0
  18. package/dist/lib/bufferStrategy.d.ts +3 -2
  19. package/dist/lib/bufferStrategy.d.ts.map +1 -1
  20. package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
  21. package/dist/lib/cloudflare/traceRows.js +3 -2
  22. package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
  23. package/dist/lib/codegen/evaluatorGenerator.js +12 -11
  24. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
  25. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
  26. package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
  27. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
  28. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
  29. package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
  30. package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
  31. package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
  32. package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
  33. package/dist/lib/convertToArrow.d.ts +7 -2
  34. package/dist/lib/convertToArrow.d.ts.map +1 -1
  35. package/dist/lib/convertToArrow.js +499 -285
  36. package/dist/lib/defineOpContext.js +1 -1
  37. package/dist/lib/enumMetadata.d.ts +19 -0
  38. package/dist/lib/enumMetadata.d.ts.map +1 -0
  39. package/dist/lib/enumMetadata.js +86 -0
  40. package/dist/lib/flushScheduler.d.ts.map +1 -1
  41. package/dist/lib/flushScheduler.js +13 -4
  42. package/dist/lib/library.d.ts +16 -98
  43. package/dist/lib/library.d.ts.map +1 -1
  44. package/dist/lib/library.js +32 -525
  45. package/dist/lib/logBinding.d.ts +21 -27
  46. package/dist/lib/logBinding.d.ts.map +1 -1
  47. package/dist/lib/op.d.ts +30 -30
  48. package/dist/lib/op.d.ts.map +1 -1
  49. package/dist/lib/op.js +15 -22
  50. package/dist/lib/opContext/createOpGroup.d.ts +1 -1
  51. package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
  52. package/dist/lib/opContext/createOpGroup.js +22 -29
  53. package/dist/lib/opContext/defineOp.d.ts +4 -4
  54. package/dist/lib/opContext/defineOp.d.ts.map +1 -1
  55. package/dist/lib/opContext/defineOp.js +53 -10
  56. package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
  57. package/dist/lib/opContext/opTypes.d.ts +1 -1
  58. package/dist/lib/opContext/opTypes.d.ts.map +1 -1
  59. package/dist/lib/opContext/spanContextTypes.d.ts +33 -18
  60. package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
  61. package/dist/lib/opContext/types.d.ts +4 -4
  62. package/dist/lib/opContext/types.d.ts.map +1 -1
  63. package/dist/lib/physicalLayoutPlan.d.ts +89 -0
  64. package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
  65. package/dist/lib/physicalLayoutPlan.js +442 -0
  66. package/dist/lib/resolveMessage.d.ts +9 -0
  67. package/dist/lib/resolveMessage.d.ts.map +1 -0
  68. package/dist/lib/resolveMessage.js +63 -0
  69. package/dist/lib/result.d.ts +5 -7
  70. package/dist/lib/result.d.ts.map +1 -1
  71. package/dist/lib/result.js +19 -26
  72. package/dist/lib/runtimeHint.d.ts +35 -0
  73. package/dist/lib/runtimeHint.d.ts.map +1 -0
  74. package/dist/lib/runtimeHint.js +79 -0
  75. package/dist/lib/schema/typeGuards.d.ts +7 -47
  76. package/dist/lib/schema/typeGuards.d.ts.map +1 -1
  77. package/dist/lib/schema/typeGuards.js +7 -123
  78. package/dist/lib/schema/types.d.ts +1 -1
  79. package/dist/lib/schema/types.d.ts.map +1 -1
  80. package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
  81. package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
  82. package/dist/lib/span-buffer/aot/v1.js +24 -0
  83. package/dist/lib/spanBuffer.d.ts +33 -4
  84. package/dist/lib/spanBuffer.d.ts.map +1 -1
  85. package/dist/lib/spanBuffer.js +583 -91
  86. package/dist/lib/spanBufferStats.d.ts +1 -1
  87. package/dist/lib/spanBufferStats.d.ts.map +1 -1
  88. package/dist/lib/spanContext.d.ts +27 -51
  89. package/dist/lib/spanContext.d.ts.map +1 -1
  90. package/dist/lib/spanContext.js +822 -344
  91. package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
  92. package/dist/lib/sqlite/sqlite-common.js +20 -21
  93. package/dist/lib/testing/bun-harness.d.ts +8 -3
  94. package/dist/lib/testing/bun-harness.d.ts.map +1 -1
  95. package/dist/lib/testing/bun-harness.js +30 -18
  96. package/dist/lib/testing/extractFacts.d.ts +1 -1
  97. package/dist/lib/testing/extractFacts.d.ts.map +1 -1
  98. package/dist/lib/testing/extractFacts.js +55 -63
  99. package/dist/lib/testing/facts.d.ts +1 -1
  100. package/dist/lib/testing/facts.d.ts.map +1 -1
  101. package/dist/lib/testing/queryable-span.d.ts +1 -1
  102. package/dist/lib/testing/queryable-span.d.ts.map +1 -1
  103. package/dist/lib/testing/queryable-span.js +26 -28
  104. package/dist/lib/testing/span-query.d.ts.map +1 -1
  105. package/dist/lib/testing/span-query.js +19 -22
  106. package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
  107. package/dist/lib/testing/stdio-replay.js +19 -8
  108. package/dist/lib/threadId.d.ts.map +1 -1
  109. package/dist/lib/threadId.js +6 -3
  110. package/dist/lib/traceContext.d.ts.map +1 -1
  111. package/dist/lib/traceContext.js +1 -4
  112. package/dist/lib/traceRoot.d.ts +30 -8
  113. package/dist/lib/traceRoot.d.ts.map +1 -1
  114. package/dist/lib/traceRoot.es.d.ts +17 -15
  115. package/dist/lib/traceRoot.es.d.ts.map +1 -1
  116. package/dist/lib/traceRoot.es.js +68 -34
  117. package/dist/lib/traceRoot.js +11 -0
  118. package/dist/lib/traceRoot.node.d.ts +17 -19
  119. package/dist/lib/traceRoot.node.d.ts.map +1 -1
  120. package/dist/lib/traceRoot.node.js +66 -38
  121. package/dist/lib/traceTopology.d.ts +42 -0
  122. package/dist/lib/traceTopology.d.ts.map +1 -0
  123. package/dist/lib/traceTopology.js +260 -0
  124. package/dist/lib/tracer.d.ts +9 -5
  125. package/dist/lib/tracer.d.ts.map +1 -1
  126. package/dist/lib/tracer.js +65 -71
  127. package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
  128. package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
  129. package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
  130. package/dist/lib/tracers/StdioTracer.js +15 -13
  131. package/dist/lib/tracers/TestTracer.d.ts +4 -6
  132. package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
  133. package/dist/lib/tracers/TestTracer.js +6 -8
  134. package/dist/lib/types.d.ts +49 -32
  135. package/dist/lib/types.d.ts.map +1 -1
  136. package/dist/lib/vocabularyRegistry.d.ts +25 -0
  137. package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
  138. package/dist/lib/vocabularyRegistry.js +372 -0
  139. package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
  140. package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
  141. package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
  142. package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
  143. package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
  144. package/dist/lib/wasm/wasmAllocator.js +66 -44
  145. package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
  146. package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
  147. package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
  148. package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
  149. package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
  150. package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
  151. package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
  152. package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
  153. package/dist/lib/wasm/wasmTraceRoot.js +110 -71
  154. package/dist/vocabulary/register/v1.d.ts +2 -0
  155. package/dist/vocabulary/register/v1.d.ts.map +1 -0
  156. package/dist/vocabulary/register/v1.js +1 -0
  157. package/dist/wasm.d.ts +5 -0
  158. package/dist/wasm.d.ts.map +1 -0
  159. package/dist/wasm.js +4 -0
  160. package/package.json +54 -6
  161. package/src/index.ts +1 -0
  162. package/src/lib/JsBufferStrategy.ts +27 -9
  163. package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
  164. package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
  165. package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
  166. package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
  167. package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
  168. package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
  169. package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
  170. package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
  171. package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
  172. package/src/lib/__tests__/capability-span-context.test.ts +505 -0
  173. package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
  174. package/src/lib/__tests__/eager-columns.test.ts +345 -0
  175. package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
  176. package/src/lib/__tests__/enum-metadata.test.ts +177 -0
  177. package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
  178. package/src/lib/__tests__/flushScheduler.test.ts +5 -1
  179. package/src/lib/__tests__/identity-view.property.test.ts +179 -0
  180. package/src/lib/__tests__/library.test.ts +19 -235
  181. package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
  182. package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
  183. package/src/lib/__tests__/op-metadata.test.ts +1 -1
  184. package/src/lib/__tests__/op-type-safety.test.ts +5 -16
  185. package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
  186. package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
  187. package/src/lib/__tests__/root-context-construction.test.ts +414 -0
  188. package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
  189. package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
  190. package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
  191. package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
  192. package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
  193. package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
  194. package/src/lib/__tests__/test-helpers.ts +67 -12
  195. package/src/lib/__tests__/threadId.test.ts +62 -0
  196. package/src/lib/__tests__/timestamp.test.ts +221 -93
  197. package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
  198. package/src/lib/__tests__/type-narrowing.test.ts +63 -0
  199. package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
  200. package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
  201. package/src/lib/arrow/lease.ts +43 -0
  202. package/src/lib/arrow/utils.ts +10 -14
  203. package/src/lib/arrow/vocabularyDictionary.ts +123 -0
  204. package/src/lib/bufferStrategy.ts +9 -1
  205. package/src/lib/cloudflare/traceRows.ts +3 -2
  206. package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
  207. package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
  208. package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
  209. package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
  210. package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
  211. package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
  212. package/src/lib/codegen/evaluatorGenerator.ts +18 -13
  213. package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
  214. package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
  215. package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
  216. package/src/lib/convertToArrow.ts +598 -311
  217. package/src/lib/defineOpContext.ts +1 -1
  218. package/src/lib/enumMetadata.ts +121 -0
  219. package/src/lib/flushScheduler.ts +11 -5
  220. package/src/lib/library.ts +37 -595
  221. package/src/lib/logBinding.ts +21 -27
  222. package/src/lib/op.ts +75 -18
  223. package/src/lib/opContext/__tests__/retry.test.ts +27 -21
  224. package/src/lib/opContext/createOpGroup.ts +33 -31
  225. package/src/lib/opContext/defineOp.ts +88 -11
  226. package/src/lib/opContext/opGroupTypes.ts +2 -2
  227. package/src/lib/opContext/opTypes.ts +1 -1
  228. package/src/lib/opContext/spanContextTypes.ts +122 -24
  229. package/src/lib/opContext/types.ts +7 -3
  230. package/src/lib/physicalLayoutPlan.ts +598 -0
  231. package/src/lib/resolveMessage.ts +67 -0
  232. package/src/lib/result.ts +20 -33
  233. package/src/lib/runtimeHint.ts +98 -0
  234. package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
  235. package/src/lib/schema/builder.ts +1 -1
  236. package/src/lib/schema/typeGuards.ts +7 -151
  237. package/src/lib/schema/types.ts +1 -1
  238. package/src/lib/span-buffer/aot/v1.ts +26 -0
  239. package/src/lib/spanBuffer.ts +658 -92
  240. package/src/lib/spanBufferStats.ts +1 -1
  241. package/src/lib/spanContext.ts +1350 -861
  242. package/src/lib/sqlite/sqlite-common.ts +20 -31
  243. package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
  244. package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
  245. package/src/lib/testing/bun-harness.ts +94 -43
  246. package/src/lib/testing/extractFacts.ts +64 -78
  247. package/src/lib/testing/facts.ts +1 -1
  248. package/src/lib/testing/queryable-span.ts +23 -30
  249. package/src/lib/testing/span-query.ts +16 -20
  250. package/src/lib/testing/stdio-replay.ts +25 -8
  251. package/src/lib/testing/vitest-harness.ts +1 -1
  252. package/src/lib/threadId.ts +6 -3
  253. package/src/lib/traceContext.ts +1 -6
  254. package/src/lib/traceRoot.es.ts +77 -42
  255. package/src/lib/traceRoot.node.ts +75 -46
  256. package/src/lib/traceRoot.ts +41 -14
  257. package/src/lib/traceTopology.ts +279 -0
  258. package/src/lib/tracer.ts +109 -98
  259. package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
  260. package/src/lib/tracers/StdioTracer.ts +15 -13
  261. package/src/lib/tracers/TestTracer.ts +6 -8
  262. package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
  263. package/src/lib/tracers/__tests__/CompositeTracer.test.ts +150 -0
  264. package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
  265. package/src/lib/types.ts +64 -33
  266. package/src/lib/vocabularyRegistry.ts +439 -0
  267. package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
  268. package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
  269. package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
  270. package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
  271. package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
  272. package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
  273. package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
  274. package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
  275. package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
  276. package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
  277. package/src/lib/wasm/wasmAllocator.ts +131 -96
  278. package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
  279. package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
  280. package/src/lib/wasm/wasmTraceRoot.ts +140 -78
  281. package/src/vocabulary/register/v1.ts +1 -0
  282. package/src/wasm.ts +19 -0
  283. package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
  284. package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
  285. package/src/lib/wasm/allocator.zig +0 -948
@@ -24,16 +24,16 @@
24
24
  *
25
25
  * @module spanBuffer
26
26
  */
27
- import { DEFAULT_BUFFER_CAPACITY, getColumnBufferClass } from '@smoothbricks/arrow-builder';
27
+ import { activeMaterializerMode, DEFAULT_BUFFER_CAPACITY, getColumnBufferClass, } from '@smoothbricks/arrow-builder';
28
28
  import { checkCapacityTuning } from './capacityTuning.js';
29
- import { textEncoder } from './spanBufferHelpers.js';
30
- import { writeThreadIdToUint64Array } from './threadId.js';
29
+ import { LogSchema } from './schema/LogSchema.js';
30
+ import { copyThreadIdTo, getThreadId } from './threadId.js';
31
+ import { getVocabularyGeneration } from './vocabularyRegistry.js';
31
32
  /**
32
33
  * Empty frozen scope object - shared singleton to avoid allocations.
33
34
  * Used as default _scopeValues for all buffers until setScope() is called.
34
35
  */
35
36
  export const EMPTY_SCOPE = Object.freeze({});
36
- const traceIdDecoder = new TextDecoder();
37
37
  // ============================================================================
38
38
  // Thread-local state (generated once per process/worker)
39
39
  // These are used by the generated class code via the constructorPreamble
@@ -91,6 +91,8 @@ function isGeneratedSpanBufferClass(ctor) {
91
91
  return false;
92
92
  }
93
93
  return (typeof Reflect.get(prototype, 'getOrCreateOverflow') === 'function' &&
94
+ typeof Reflect.get(prototype, '_sealStats') === 'function' &&
95
+ typeof Reflect.get(prototype, '_sealStatsChain') === 'function' &&
94
96
  typeof Reflect.get(prototype, 'isParentOf') === 'function' &&
95
97
  typeof Reflect.get(prototype, 'isChildOf') === 'function');
96
98
  }
@@ -106,21 +108,396 @@ function getSpanBufferConstructorForBuffer(buffer) {
106
108
  }
107
109
  return ctor;
108
110
  }
109
- function createSpanBufferConstructor(schema, generatedClass) {
110
- return Object.assign(generatedClass, {
111
- schema,
111
+ function createSpanBufferConstructor(schema, messageLayoutFamily, messagePhysicalLayout, generatedClass, eagerColumns) {
112
+ Object.defineProperties(generatedClass, {
113
+ schema: { value: schema, enumerable: true },
114
+ messageLayoutFamily: { value: messageLayoutFamily, enumerable: true },
115
+ messagePhysicalLayout: { value: messagePhysicalLayout, enumerable: true },
116
+ eagerColumns: { value: eagerColumns, enumerable: true },
112
117
  stats: {
113
- capacity: DEFAULT_BUFFER_CAPACITY,
114
- totalWrites: 0,
115
- spansCreated: 0,
118
+ value: {
119
+ capacity: DEFAULT_BUFFER_CAPACITY,
120
+ totalWrites: 0,
121
+ spansCreated: 0,
122
+ },
123
+ enumerable: true,
116
124
  },
117
125
  });
126
+ if (!isSpanBufferConstructorForSchema(generatedClass, schema)) {
127
+ throw new TypeError('Generated column buffer constructor initialization failed');
128
+ }
129
+ return generatedClass;
118
130
  }
119
131
  /**
120
132
  * Cache for generated SpanBuffer classes per schema.
121
133
  * Key is the schema object reference (WeakMap for GC).
122
134
  */
123
135
  const spanBufferClassCache = new WeakMap();
136
+ const messageStorageSchemas = new WeakMap();
137
+ const EMPTY_EAGER_COLUMNS = Object.freeze({
138
+ names: Object.freeze([]),
139
+ words: Object.freeze([]),
140
+ key: '',
141
+ });
142
+ function resolveCompiledEagerColumns(schema, requestedNames) {
143
+ if (requestedNames.length === 0)
144
+ return EMPTY_EAGER_COLUMNS;
145
+ const requested = new Set(requestedNames);
146
+ const names = [];
147
+ const words = new Array(Math.ceil(schema._columnNames.length / 32)).fill(0);
148
+ for (let columnIndex = 0; columnIndex < schema._columnNames.length; columnIndex++) {
149
+ const name = schema._columnNames[columnIndex];
150
+ if (!requested.delete(name))
151
+ continue;
152
+ names.push(name);
153
+ const wordIndex = columnIndex >>> 5;
154
+ words[wordIndex] = (words[wordIndex] | (1 << (columnIndex & 31))) >>> 0;
155
+ }
156
+ if (requested.size !== 0) {
157
+ throw new TypeError(`Unknown compiled eager column${requested.size === 1 ? '' : 's'}: ${[...requested].join(', ')}`);
158
+ }
159
+ while (words.length !== 0 && words[words.length - 1] === 0)
160
+ words.pop();
161
+ const frozenWords = Object.freeze(words);
162
+ return Object.freeze({
163
+ names: Object.freeze(names),
164
+ words: frozenWords,
165
+ key: frozenWords.map((word) => word.toString(16).padStart(8, '0')).join(''),
166
+ });
167
+ }
168
+ function getStorageSchema(schema, messageLayoutFamily, messagePhysicalLayout) {
169
+ let byLayout = messageStorageSchemas.get(schema);
170
+ const key = `${messageLayoutFamily}:${messagePhysicalLayout}`;
171
+ let storageSchema = byLayout?.get(key);
172
+ if (storageSchema === undefined) {
173
+ const fields = {};
174
+ for (const [name, field] of schema._columns) {
175
+ if (name !== 'message')
176
+ fields[name] = field;
177
+ }
178
+ storageSchema = new LogSchema(fields);
179
+ byLayout ??= new Map();
180
+ byLayout.set(key, storageSchema);
181
+ messageStorageSchemas.set(schema, byLayout);
182
+ }
183
+ return storageSchema;
184
+ }
185
+ /**
186
+ * Canonicalize a ttsc-emitted SpanBuffer class into the same schema/layout cache
187
+ * used by the dynamic fallback. The factory is lazy so an already materialized
188
+ * class wins without allocating a duplicate constructor.
189
+ */
190
+ export function materializeCompiledSpanBufferClass(schema, messageLayoutFamily, messagePhysicalLayout, eagerColumnNames, factory) {
191
+ const eagerColumns = resolveCompiledEagerColumns(schema, eagerColumnNames);
192
+ // Mode-prefixed like arrow-builder's class caches: the materializer mode is fixed for a process,
193
+ // but the parity suite flips it via override and must never see the other mode's class.
194
+ const cacheKey = `${activeMaterializerMode()}:${messageLayoutFamily}:${messagePhysicalLayout}:${eagerColumns.key}`;
195
+ let familyClasses = spanBufferClassCache.get(schema);
196
+ const cached = familyClasses?.get(cacheKey);
197
+ if (isSpanBufferConstructorForSchema(cached, schema) &&
198
+ cached.messageLayoutFamily === messageLayoutFamily &&
199
+ cached.messagePhysicalLayout === messagePhysicalLayout) {
200
+ return cached;
201
+ }
202
+ const compiledClass = factory();
203
+ if (!isGeneratedSpanBufferClass(compiledClass)) {
204
+ throw new TypeError('Compiled SpanBuffer class is missing the required buffer contract');
205
+ }
206
+ const SpanBufferClass = createSpanBufferConstructor(schema, messageLayoutFamily, messagePhysicalLayout, compiledClass, eagerColumns);
207
+ familyClasses ??= new Map();
208
+ familyClasses.set(cacheKey, SpanBufferClass);
209
+ spanBufferClassCache.set(schema, familyClasses);
210
+ return SpanBufferClass;
211
+ }
212
+ function isSpanBufferConstructorValue(value) {
213
+ return typeof value === 'function';
214
+ }
215
+ function spanBufferStatics(self) {
216
+ const ctor = self.constructor;
217
+ if (!isSpanBufferConstructorValue(ctor))
218
+ throw new TypeError('SpanBuffer constructor is not initialized');
219
+ return ctor;
220
+ }
221
+ /** Constructor arguments arrive untyped through the materializer; every real buffer/traceRoot is an object. */
222
+ function isSpanBufferValue(value) {
223
+ return typeof value === 'object' && value !== null;
224
+ }
225
+ function isTraceRootValue(value) {
226
+ return typeof value === 'object' && value !== null;
227
+ }
228
+ function requireParent(parent) {
229
+ if (parent === undefined)
230
+ throw new TypeError('Chained/child SpanBuffer construction requires a parent buffer');
231
+ return parent;
232
+ }
233
+ /** Every runtime SpanBuffer instance satisfies the typed SpanBuffer contract (dynamic column lanes included). */
234
+ function isTypedSpanBuffer(value) {
235
+ return typeof value === 'object' && value !== null;
236
+ }
237
+ /** Mirrors the generated `_sealStats` body (shared with getOrCreateOverflow). */
238
+ function sealStatsFor(self) {
239
+ if (self._statsSealed)
240
+ return;
241
+ const completedRows = self._writeIndex - self._statsReservedRows;
242
+ if (completedRows > 0)
243
+ spanBufferStatics(self).stats.totalWrites += completedRows;
244
+ self._statsSealed = true;
245
+ }
246
+ /**
247
+ * No-eval counterpart of the extension `constructorPreamble` (and its
248
+ * `constructorParams` signature): identical buffer-type branches (root /
249
+ * child / chained), identical physical system layout math, identical
250
+ * property-assignment order (V8 in-object slots).
251
+ */
252
+ function createSpanBufferClosureInit(messageLayoutFamily, messagePhysicalLayout) {
253
+ return (self, requestedCapacity, ctorArgs) => {
254
+ // ctorArgs mirror constructorParams: stats, parent, isChained, callsiteMetadata, opMetadata, traceRoot, vocabularyGeneration
255
+ const parent = isSpanBufferValue(ctorArgs[1]) ? ctorArgs[1] : undefined;
256
+ const isChained = Boolean(ctorArgs[2]);
257
+ const callsiteMetadata = ctorArgs[3];
258
+ const opMetadata = ctorArgs[4];
259
+ const traceRootArg = ctorArgs[5];
260
+ if (!isTraceRootValue(traceRootArg))
261
+ throw new TypeError('SpanBuffer construction requires a traceRoot');
262
+ const traceRoot = traceRootArg;
263
+ const vocabularyGeneration = ctorArgs[6];
264
+ // Thread-local span counter (per-process/worker, see threadId.ts docs)
265
+ globalThis.globalSpanCounter = (globalThis.globalSpanCounter ?? 0) + 1;
266
+ const spanId = globalThis.globalSpanCounter;
267
+ const threadId = isChained ? requireParent(parent).thread_id : getThreadId();
268
+ // Calculate exact physical system storage (same math as the preamble variants).
269
+ let systemSize;
270
+ let rowHeaderOffset = 0;
271
+ let messageIdOffset = 0;
272
+ let logHeaderOffset = 0;
273
+ if (messagePhysicalLayout === 'packed') {
274
+ rowHeaderOffset = requestedCapacity * 8;
275
+ systemSize = (requestedCapacity * 12 + 7) & ~7;
276
+ }
277
+ else if (messageLayoutFamily === 'dynamic-only') {
278
+ systemSize = (requestedCapacity * 9 + 7) & ~7;
279
+ }
280
+ else if (messagePhysicalLayout === 'current') {
281
+ messageIdOffset = (requestedCapacity * 9 + 1) & ~1;
282
+ systemSize = (messageIdOffset + requestedCapacity * 2 + 7) & ~7;
283
+ }
284
+ else {
285
+ logHeaderOffset = (requestedCapacity * 9 + 3) & ~3;
286
+ systemSize = (logHeaderOffset + requestedCapacity * 4 + 7) & ~7;
287
+ }
288
+ // CHAINED: shares parent._identity; CHILD: identity without traceId; ROOT: identity with traceId bytes.
289
+ let systemBuffer;
290
+ let identityView;
291
+ if (isChained) {
292
+ systemBuffer = new ArrayBuffer(systemSize);
293
+ identityView = requireParent(parent)._identity;
294
+ }
295
+ else if (parent) {
296
+ const identitySize = 12;
297
+ systemBuffer = new ArrayBuffer(systemSize + identitySize);
298
+ identityView = new Uint8Array(systemBuffer, systemSize, identitySize);
299
+ copyThreadIdTo(identityView, 0);
300
+ identityView[8] = spanId;
301
+ identityView[9] = spanId >>> 8;
302
+ identityView[10] = spanId >>> 16;
303
+ identityView[11] = spanId >>> 24;
304
+ }
305
+ else {
306
+ const traceIdBytes = traceRoot._traceIdBytes;
307
+ const identitySize = 13 + traceIdBytes.length;
308
+ systemBuffer = new ArrayBuffer(systemSize + identitySize);
309
+ identityView = new Uint8Array(systemBuffer, systemSize, identitySize);
310
+ copyThreadIdTo(identityView, 0);
311
+ identityView[8] = spanId;
312
+ identityView[9] = spanId >>> 8;
313
+ identityView[10] = spanId >>> 16;
314
+ identityView[11] = spanId >>> 24;
315
+ identityView[12] = traceIdBytes.length;
316
+ identityView.set(traceIdBytes, 13);
317
+ }
318
+ // Assign properties in the optimal V8 in-object slot order (same as the preamble).
319
+ self._writeIndex = 0;
320
+ self._capacity = requestedCapacity;
321
+ self._overflow = undefined;
322
+ self.timestamp = new BigInt64Array(systemBuffer, 0, requestedCapacity);
323
+ if (messagePhysicalLayout === 'packed') {
324
+ self._rowHeaders = new Uint32Array(systemBuffer, rowHeaderOffset, requestedCapacity);
325
+ }
326
+ else {
327
+ self.entry_type = new Uint8Array(systemBuffer, requestedCapacity * 8, requestedCapacity);
328
+ if (messageLayoutFamily !== 'dynamic-only') {
329
+ if (messagePhysicalLayout === 'current') {
330
+ self._messageIds = new Uint16Array(systemBuffer, messageIdOffset, requestedCapacity);
331
+ }
332
+ else {
333
+ self._logHeaders = new Uint32Array(systemBuffer, logHeaderOffset, requestedCapacity);
334
+ }
335
+ }
336
+ }
337
+ self._vocabularyGeneration = vocabularyGeneration;
338
+ if (messageLayoutFamily === 'static-only') {
339
+ self._spanName = undefined;
340
+ self._terminalMessage = undefined;
341
+ }
342
+ else if (messageLayoutFamily === 'dynamic-only') {
343
+ self._spanName = undefined;
344
+ }
345
+ self._nodeIndex = 4294967295;
346
+ self._topologyGeneration = 0;
347
+ self._parent = isChained ? requireParent(parent)._parent : parent;
348
+ self._traceRoot = traceRoot;
349
+ self._scopeValues = parent ? parent._scopeValues : EMPTY_SCOPE;
350
+ self._threadId = threadId;
351
+ self._identity = identityView;
352
+ self._system = systemBuffer;
353
+ self._callsiteMetadata = callsiteMetadata;
354
+ self._opMetadata = opMetadata;
355
+ self._statsSealed = false;
356
+ self._statsReservedRows = isChained ? 0 : 2;
357
+ if (messageLayoutFamily !== 'static-only') {
358
+ self.message_values = new Array(requestedCapacity);
359
+ }
360
+ };
361
+ }
362
+ /**
363
+ * No-eval counterpart of the extension `methods` string: same members, same
364
+ * kinds (getter vs method), installed after the generated per-column members
365
+ * so same-named members override exactly like the compiled class body.
366
+ */
367
+ function createSpanBufferClosureMethods(messageLayoutFamily) {
368
+ return (prototype) => {
369
+ const defineMethod = (name, value) => {
370
+ Object.defineProperty(prototype, name, { value, writable: true, configurable: true, enumerable: false });
371
+ };
372
+ const defineGetter = (name, get) => {
373
+ Object.defineProperty(prototype, name, { get, configurable: true, enumerable: false });
374
+ };
375
+ defineGetter('span_id', function () {
376
+ const b = this._identity;
377
+ return b ? (b[8] | (b[9] << 8) | (b[10] << 16) | (b[11] << 24)) >>> 0 : 0;
378
+ });
379
+ defineGetter('thread_id', function () {
380
+ return this._threadId;
381
+ });
382
+ defineGetter('trace_id', function () {
383
+ return this._traceRoot.trace_id;
384
+ });
385
+ defineGetter('_spanStartTime', function () {
386
+ return this.timestamp[0];
387
+ });
388
+ defineGetter('_lastLoggedTime', function () {
389
+ const chain = [];
390
+ let current = this;
391
+ while (current) {
392
+ chain.push(current);
393
+ current = current._overflow;
394
+ }
395
+ for (let i = chain.length - 1; i >= 0; i--) {
396
+ const buffer = chain[i];
397
+ for (let row = buffer._writeIndex - 1; row >= 0; row--) {
398
+ const ts = buffer.timestamp[row];
399
+ if (ts !== 0n) {
400
+ return ts;
401
+ }
402
+ }
403
+ }
404
+ return null;
405
+ });
406
+ defineGetter('_hasParent', function () {
407
+ return this._parent !== undefined;
408
+ });
409
+ defineGetter('parent_span_id', function () {
410
+ return this._parent?.span_id ?? 0;
411
+ });
412
+ defineGetter('parent_thread_id', function () {
413
+ return this._parent?.thread_id ?? 0n;
414
+ });
415
+ defineMethod('isParentOf', function (other) {
416
+ return this === other._parent;
417
+ });
418
+ defineMethod('isChildOf', function (other) {
419
+ return this._parent === other;
420
+ });
421
+ defineMethod('copyThreadIdTo', function (dest, offset) {
422
+ const source = this._identity;
423
+ if (source) {
424
+ dest[offset] = source[0];
425
+ dest[offset + 1] = source[1];
426
+ dest[offset + 2] = source[2];
427
+ dest[offset + 3] = source[3];
428
+ dest[offset + 4] = source[4];
429
+ dest[offset + 5] = source[5];
430
+ dest[offset + 6] = source[6];
431
+ dest[offset + 7] = source[7];
432
+ }
433
+ else {
434
+ dest.fill(0, offset, offset + 8);
435
+ }
436
+ });
437
+ defineMethod('copyParentThreadIdTo', function (dest, offset) {
438
+ if (this._parent)
439
+ this._parent.copyThreadIdTo(dest, offset);
440
+ else
441
+ dest.fill(0, offset, offset + 8);
442
+ });
443
+ defineGetter('_logSchema', function () {
444
+ return spanBufferStatics(this).schema;
445
+ });
446
+ defineGetter('_messageLayoutFamily', function () {
447
+ return spanBufferStatics(this).messageLayoutFamily;
448
+ });
449
+ defineGetter('_messagePhysicalLayout', function () {
450
+ return spanBufferStatics(this).messagePhysicalLayout;
451
+ });
452
+ defineGetter('_columns', function () {
453
+ return spanBufferStatics(this).schema._columns;
454
+ });
455
+ defineGetter('_stats', function () {
456
+ return spanBufferStatics(this).stats;
457
+ });
458
+ defineMethod('_sealStats', function () {
459
+ sealStatsFor(this);
460
+ });
461
+ defineMethod('_sealStatsChain', function () {
462
+ let current = this;
463
+ while (current) {
464
+ sealStatsFor(current);
465
+ current = current._overflow;
466
+ }
467
+ });
468
+ defineMethod('getOrCreateOverflow', function () {
469
+ if (this._overflow)
470
+ return this._overflow;
471
+ sealStatsFor(this);
472
+ const tracer = this._traceRoot.tracer;
473
+ tracer.onStatsWillResetFor(this);
474
+ checkCapacityTuning(spanBufferStatics(this).stats);
475
+ if (!isTypedSpanBuffer(this))
476
+ throw new TypeError('SpanBuffer instance is not initialized');
477
+ return tracer.bufferStrategy.createOverflowBuffer(this);
478
+ });
479
+ if (messageLayoutFamily === 'static-only') {
480
+ defineMethod('message', function (pos, val) {
481
+ if (pos === 0)
482
+ this._spanName = val;
483
+ else if (pos === 1)
484
+ this._terminalMessage = val;
485
+ else
486
+ throw new RangeError('Static-only buffers only accept raw system messages at rows 0 and 1');
487
+ return this;
488
+ });
489
+ }
490
+ else {
491
+ defineMethod('message', function (pos, val) {
492
+ const lane = this.message_values;
493
+ if (!Array.isArray(lane))
494
+ throw new TypeError('message_values lane is not allocated');
495
+ lane[pos] = val;
496
+ return this;
497
+ });
498
+ }
499
+ };
500
+ }
124
501
  /**
125
502
  * Get or create a SpanBuffer class for the given schema.
126
503
  *
@@ -134,9 +511,13 @@ const spanBufferClassCache = new WeakMap();
134
511
  * @returns SpanBufferConstructor with static schema and stats properties
135
512
  */
136
513
  //#region smoo/lmao!n/spanbuffer-layout.constructor
137
- export function getSpanBufferClass(schema) {
138
- const cached = spanBufferClassCache.get(schema);
139
- if (isSpanBufferConstructorForSchema(cached, schema)) {
514
+ export function getSpanBufferClass(schema, messageLayoutFamily = 'mixed', messagePhysicalLayout = 'current', eagerColumns = EMPTY_EAGER_COLUMNS) {
515
+ const cacheKey = `${activeMaterializerMode()}:${messageLayoutFamily}:${messagePhysicalLayout}:${eagerColumns.key}`;
516
+ let familyClasses = spanBufferClassCache.get(schema);
517
+ const cached = familyClasses?.get(cacheKey);
518
+ if (isSpanBufferConstructorForSchema(cached, schema) &&
519
+ cached.messageLayoutFamily === messageLayoutFamily &&
520
+ cached.messagePhysicalLayout === messagePhysicalLayout) {
140
521
  return cached;
141
522
  }
142
523
  // ==========================================================================
@@ -159,21 +540,27 @@ export function getSpanBufferClass(schema) {
159
540
  // 2. _capacity - compared on EVERY write (overflow check)
160
541
  // 3. _overflow - checked when overflow occurs
161
542
  // 4. timestamp/entry_type - TypedArray refs accessed on EVERY write
162
- // 5. _children/_parent - modified/accessed during span creation
543
+ // 5. _nodeIndex/_parent - modified/accessed during span creation
163
544
  // 6. _traceRoot - accessed for timestamp anchors on EVERY write
164
545
  // 7. _identity/_logBinding - accessed during span operations
165
546
  // 8-N. Cold properties - only accessed during Arrow conversion
166
547
  // ==========================================================================
167
548
  // Define extension for arrow-builder's class generator
168
549
  const extension = {
169
- constructorParams: 'stats, parent, isChained, callsiteMetadata, opMetadata, traceRoot',
550
+ preallocatedColumns: eagerColumns.names,
551
+ constructorParams: 'stats, parent, isChained, callsiteMetadata, opMetadata, traceRoot, vocabularyGeneration',
170
552
  dependencies: {
171
- writeThreadIdToUint64Array,
172
- textDecoder: traceIdDecoder,
173
- textEncoder,
553
+ copyThreadIdTo,
554
+ getThreadId,
174
555
  EMPTY_SCOPE,
175
556
  checkCapacityTuning,
176
557
  },
558
+ // No-eval counterparts consumed by arrow-builder's closure-composed
559
+ // materializer on runtimes without string codegen (workerd). They MUST
560
+ // mirror constructorPreamble/methods below exactly — see the factories
561
+ // above and spanbuffer-materializer-parity.test.ts.
562
+ closureInit: createSpanBufferClosureInit(messageLayoutFamily, messagePhysicalLayout),
563
+ closureMethods: createSpanBufferClosureMethods(messageLayoutFamily),
177
564
  // ==========================================================================
178
565
  // GENERATED CONSTRUCTOR PREAMBLE
179
566
  // ==========================================================================
@@ -199,12 +586,11 @@ export function getSpanBufferClass(schema) {
199
586
  // V8 IN-OBJECT PROPERTY OPTIMIZATION:
200
587
  // Property assignment order determines which properties get fast in-object slots.
201
588
  // First ~10-12 properties are stored directly on the object (fastest access).
202
- // Slots 1-3: HOTTEST (every log entry) - _writeIndex, _capacity, _overflow
203
- // Slots 4-5: HOT (TypedArray refs) - timestamp, entry_type
204
- // Slots 6-7: WARM (tree structure) - _children, _parent
205
- // Slots 8-10: WARM (context) - _traceRoot, _scopeValues, _identity
206
- // Slots 11: WARM (system) - _system
207
- // Slots 12+: COLD (Arrow conversion only) - _callsiteMetadata, _opMetadata
589
+ // Slots 0-2: HOTTEST (every log entry) - _writeIndex, _capacity, _overflow
590
+ // Slots 3-6: HOT (storage refs) - timestamp, entry_type/header, message identity, vocabulary
591
+ // Slots 7-10: WARM (tree structure) - _nodeIndex, _topologyGeneration, _parent, _traceRoot
592
+ // Slots 11-14: WARM (context/identity) - _scopeValues, _threadId, _identity, _system
593
+ // Slots 15+: COLD (Arrow/stats/raw message) - metadata, stats, message_values
208
594
  // ==========================================================================
209
595
  constructorPreamble:
210
596
  // Thread-local span counter (per-process/worker, see threadId.ts docs)
@@ -212,84 +598,133 @@ export function getSpanBufferClass(schema) {
212
598
  globalThis.globalSpanCounter = 0;
213
599
  }
214
600
  const spanId = ++globalThis.globalSpanCounter;
601
+ const threadId = isChained ? parent.thread_id : getThreadId();
215
602
  ` +
216
- // Calculate system buffer size: timestamps (8 bytes * cap) + entry_type (1 byte * cap)
217
- // Align to 8 bytes so identity's BigUint64Array offset is aligned
218
- `const rawSystemSize = requestedCapacity * 9;
219
- const systemSize = (rawSystemSize + 7) & ~7;
603
+ // Calculate exact physical system storage once for the generated class.
604
+ (messagePhysicalLayout === 'packed'
605
+ ? `const rowHeaderOffset = requestedCapacity * 8;
606
+ const systemSize = (requestedCapacity * 12 + 7) & ~7;
220
607
  let systemBuffer;
221
608
  let identityView;
222
- ` +
609
+ `
610
+ : messageLayoutFamily === 'dynamic-only'
611
+ ? `const systemSize = (requestedCapacity * 9 + 7) & ~7;
612
+ let systemBuffer;
613
+ let identityView;
614
+ `
615
+ : messagePhysicalLayout === 'current'
616
+ ? `const messageIdOffset = (requestedCapacity * 9 + 1) & ~1;
617
+ const systemSize = (messageIdOffset + requestedCapacity * 2 + 7) & ~7;
618
+ let systemBuffer;
619
+ let identityView;
620
+ `
621
+ : `const logHeaderOffset = (requestedCapacity * 9 + 3) & ~3;
622
+ const systemSize = (logHeaderOffset + requestedCapacity * 4 + 7) & ~7;
623
+ let systemBuffer;
624
+ let identityView;
625
+ `) +
223
626
  // CHAINED BUFFER: overflow storage for same logical span - shares parent identity
224
627
  `if (isChained) {
225
628
  systemBuffer = new ArrayBuffer(systemSize);
226
629
  identityView = parent._identity;
227
630
  }` +
228
631
  // CHILD BUFFER: new span in existing trace - gets identity without traceId
229
- // (traceId accessed via parent chain walk in trace_id getter)
230
632
  ` else if (parent) {
231
633
  const identitySize = 12;
232
634
  systemBuffer = new ArrayBuffer(systemSize + identitySize);
233
635
  identityView = new Uint8Array(systemBuffer, systemSize, identitySize);
234
- const threadIdArray = new BigUint64Array(systemBuffer, systemSize, 1);
235
- writeThreadIdToUint64Array(threadIdArray, 0);
236
- new DataView(systemBuffer, systemSize).setUint32(8, spanId, true);
636
+ copyThreadIdTo(identityView, 0);
637
+ identityView[8] = spanId;
638
+ identityView[9] = spanId >>> 8;
639
+ identityView[10] = spanId >>> 16;
640
+ identityView[11] = spanId >>> 24;
237
641
  }` +
238
- // ROOT BUFFER: new trace - gets identity with traceId from TraceRoot
642
+ // ROOT BUFFER: new trace - copies the trace-owned canonical bytes once into its public identity.
239
643
  ` else {
240
- const traceIdUtf8 = textEncoder.encode(traceRoot.trace_id);
241
- const identitySize = 13 + traceIdUtf8.length;
644
+ const traceIdBytes = traceRoot._traceIdBytes;
645
+ const identitySize = 13 + traceIdBytes.length;
242
646
  systemBuffer = new ArrayBuffer(systemSize + identitySize);
243
647
  identityView = new Uint8Array(systemBuffer, systemSize, identitySize);
244
- const view = new DataView(systemBuffer, systemSize);
245
- const threadIdArray = new BigUint64Array(systemBuffer, systemSize, 1);
246
- writeThreadIdToUint64Array(threadIdArray, 0);
247
- view.setUint32(8, spanId, true);
248
- identityView[12] = traceIdUtf8.length;
249
- identityView.set(traceIdUtf8, 13);
648
+ copyThreadIdTo(identityView, 0);
649
+ identityView[8] = spanId;
650
+ identityView[9] = spanId >>> 8;
651
+ identityView[10] = spanId >>> 16;
652
+ identityView[11] = spanId >>> 24;
653
+ identityView[12] = traceIdBytes.length;
654
+ identityView.set(traceIdBytes, 13);
250
655
  }
251
656
  ` +
252
- // Create TypedArray views for timestamps and entry_type
253
- `const timestampView = new BigInt64Array(systemBuffer, 0, requestedCapacity);
657
+ // Create exact physical views. Packed classes never create split entry/header views.
658
+ (messagePhysicalLayout === 'packed'
659
+ ? `const timestampView = new BigInt64Array(systemBuffer, 0, requestedCapacity);
660
+ const rowHeaderView = new Uint32Array(systemBuffer, rowHeaderOffset, requestedCapacity);
661
+ `
662
+ : `const timestampView = new BigInt64Array(systemBuffer, 0, requestedCapacity);
254
663
  const entryTypeView = new Uint8Array(systemBuffer, requestedCapacity * 8, requestedCapacity);
255
- timestampView.fill(0n);
256
- entryTypeView.fill(0);
257
664
  ` +
258
- // Assign properties in optimal order for V8 in-object slots (see comment above)
665
+ (messageLayoutFamily === 'dynamic-only'
666
+ ? ''
667
+ : messagePhysicalLayout === 'current'
668
+ ? ` const messageIdView = new Uint16Array(systemBuffer, messageIdOffset, requestedCapacity);
669
+ `
670
+ : ` const logHeaderView = new Uint32Array(systemBuffer, logHeaderOffset, requestedCapacity);
671
+ `)) +
672
+ // Assign properties in optimal order for V8 in-object slots.
259
673
  `this._writeIndex = 0;
260
674
  this._capacity = requestedCapacity;
261
675
  this._overflow = undefined;
262
676
  this.timestamp = timestampView;
263
- this.entry_type = entryTypeView;
264
- this._children = [];
677
+ ` +
678
+ (messagePhysicalLayout === 'packed'
679
+ ? ` this._rowHeaders = rowHeaderView;
680
+ `
681
+ : ` this.entry_type = entryTypeView;
682
+ ` +
683
+ (messageLayoutFamily === 'dynamic-only'
684
+ ? ''
685
+ : messagePhysicalLayout === 'current'
686
+ ? ` this._messageIds = messageIdView;
687
+ `
688
+ : ` this._logHeaders = logHeaderView;
689
+ `)) +
690
+ ` this._vocabularyGeneration = vocabularyGeneration;
691
+ ` +
692
+ (messageLayoutFamily === 'static-only'
693
+ ? ` this._spanName = undefined;
694
+ this._terminalMessage = undefined;
695
+ `
696
+ : messageLayoutFamily === 'dynamic-only'
697
+ ? ` this._spanName = undefined;
698
+ `
699
+ : '') +
700
+ ` this._nodeIndex = 4294967295;
701
+ this._topologyGeneration = 0;
265
702
  this._parent = isChained ? parent._parent : parent;
266
703
  this._traceRoot = traceRoot;
267
704
  this._scopeValues = parent ? parent._scopeValues : EMPTY_SCOPE;
705
+ this._threadId = threadId;
268
706
  this._identity = identityView;
269
707
  this._system = systemBuffer;
270
708
  this._callsiteMetadata = callsiteMetadata;
271
709
  this._opMetadata = opMetadata;
272
- `,
273
- // Generated methods for SpanBuffer - no comments in output
274
- // span_id: extract from identity bytes [8:12]
275
- // thread_id: extract from identity bytes [0:8]
276
- // trace_id: walk up parent chain to root, decode trace_id from identity
277
- // parent_span_id/parent_thread_id: delegate to parent
278
- // isParentOf/isChildOf: pointer comparison
279
- // copyThreadIdTo/copyParentThreadIdTo: copy thread_id bytes to destination
710
+ this._statsSealed = false;
711
+ this._statsReservedRows = isChained ? 0 : 2;
712
+ ` +
713
+ (messageLayoutFamily === 'static-only'
714
+ ? ''
715
+ : ` this.message_values = new Array(requestedCapacity);
716
+ `) +
717
+ ' ',
718
+ // Generated identity methods use canonical primitives/direct offsets without temporary views.
280
719
  methods: `get span_id() {
281
- return this._identity ? new DataView(this._identity.buffer, this._identity.byteOffset + 8).getUint32(0, true) : 0;
720
+ const b = this._identity;
721
+ return b ? (b[8] | (b[9] << 8) | (b[10] << 16) | (b[11] << 24)) >>> 0 : 0;
282
722
  }
283
723
  get thread_id() {
284
- return this._identity ? new DataView(this._identity.buffer, this._identity.byteOffset).getBigUint64(0, true) : 0n;
724
+ return this._threadId;
285
725
  }
286
726
  get trace_id() {
287
- let current = this;
288
- while (current._parent) { current = current._parent; }
289
- if (!current._identity) { return undefined; }
290
- const len = current._identity[12];
291
- const traceIdBytes = current._identity.subarray(13, 13 + len);
292
- return textDecoder.decode(traceIdBytes);
727
+ return this._traceRoot.trace_id;
293
728
  }
294
729
  get _spanStartTime() {
295
730
  return this.timestamp[0];
@@ -318,39 +753,78 @@ export function getSpanBufferClass(schema) {
318
753
  isParentOf(other) { return this === other._parent; }
319
754
  isChildOf(other) { return this._parent === other; }
320
755
  copyThreadIdTo(dest, offset) {
321
- if (this._identity) {
322
- const view = new DataView(this._identity.buffer, this._identity.byteOffset);
323
- const threadId = view.getBigUint64(0, true);
324
- new DataView(dest.buffer, dest.byteOffset + offset).setBigUint64(0, threadId, true);
756
+ const source = this._identity;
757
+ if (source) {
758
+ dest[offset] = source[0];
759
+ dest[offset + 1] = source[1];
760
+ dest[offset + 2] = source[2];
761
+ dest[offset + 3] = source[3];
762
+ dest[offset + 4] = source[4];
763
+ dest[offset + 5] = source[5];
764
+ dest[offset + 6] = source[6];
765
+ dest[offset + 7] = source[7];
325
766
  } else {
326
- new DataView(dest.buffer, dest.byteOffset + offset).setBigUint64(0, 0n, true);
767
+ dest.fill(0, offset, offset + 8);
327
768
  }
328
769
  }
329
770
  copyParentThreadIdTo(dest, offset) {
330
- this._parent?.copyThreadIdTo(dest, offset) ?? new DataView(dest.buffer, dest.byteOffset + offset).setBigUint64(0, 0n, true);
771
+ if (this._parent) this._parent.copyThreadIdTo(dest, offset);
772
+ else dest.fill(0, offset, offset + 8);
331
773
  }
332
774
  get _logSchema() { return this.constructor.schema; }
775
+ get _messageLayoutFamily() { return this.constructor.messageLayoutFamily; }
776
+ get _messagePhysicalLayout() { return this.constructor.messagePhysicalLayout; }
333
777
  get _columns() { return this.constructor.schema._columns; }
334
778
  get _stats() { return this.constructor.stats; }
779
+ _sealStats() {
780
+ if (this._statsSealed) return;
781
+ const completedRows = this._writeIndex - this._statsReservedRows;
782
+ if (completedRows > 0) this.constructor.stats.totalWrites += completedRows;
783
+ this._statsSealed = true;
784
+ }
785
+ _sealStatsChain() {
786
+ let current = this;
787
+ while (current) {
788
+ current._sealStats();
789
+ current = current._overflow;
790
+ }
791
+ }
335
792
  getOrCreateOverflow() {
336
793
  if (this._overflow) return this._overflow;
794
+ this._sealStats();
337
795
  const tracer = this._traceRoot.tracer;
338
796
  tracer.onStatsWillResetFor(this);
339
797
  checkCapacityTuning(this.constructor.stats);
340
798
  return tracer.bufferStrategy.createOverflowBuffer(this);
341
799
  }
800
+ ${messageLayoutFamily === 'static-only'
801
+ ? `message(pos, val) {
802
+ if (pos === 0) this._spanName = val;
803
+ else if (pos === 1) this._terminalMessage = val;
804
+ else throw new RangeError('Static-only buffers only accept raw system messages at rows 0 and 1');
805
+ return this;
806
+ }`
807
+ : `message(pos, val) {
808
+ this.message_values[pos] = val;
809
+ return this;
810
+ }`}
342
811
  `,
343
812
  };
813
+ // Storage schema identity partitions source schema/family/physical classes; the extension cache key
814
+ // partitions eager-column selections without adding another dedicated cache object.
815
+ const storageSchema = getStorageSchema(schema, messageLayoutFamily, messagePhysicalLayout);
344
816
  // Generate class with arrow-builder
345
- const generatedClass = getColumnBufferClass(schema, extension);
817
+ const generatedClass = getColumnBufferClass(storageSchema, extension, storageSchema);
346
818
  if (!isGeneratedSpanBufferClass(generatedClass)) {
347
819
  throw new TypeError('Generated column buffer is missing SpanBuffer methods');
348
820
  }
349
- // Add static properties to the generated class
350
- // These are shared across all instances from the same defineOpContext
351
- const SpanBufferClass = createSpanBufferConstructor(schema, generatedClass);
821
+ // Initialize immutable static discriminators before publishing the constructor in the LMAO cache.
822
+ // The mutable stats object remains shared by every instance of this exact class dimension.
823
+ const SpanBufferClass = createSpanBufferConstructor(schema, messageLayoutFamily, messagePhysicalLayout, generatedClass, eagerColumns);
352
824
  // Cache for future use
353
- spanBufferClassCache.set(schema, SpanBufferClass);
825
+ familyClasses ??= new Map();
826
+ familyClasses.set(cacheKey, SpanBufferClass);
827
+ spanBufferClassCache.set(schema, familyClasses);
354
828
  return SpanBufferClass;
355
829
  }
356
830
  //#endregion smoo/lmao!n/spanbuffer-layout.constructor
@@ -369,22 +843,35 @@ export function getSpanBufferClass(schema) {
369
843
  *
370
844
  * @returns SpanBuffer with typed setters for schema fields
371
845
  */
372
- const MIN_CAPACITY = 8;
846
+ export const MIN_ADAPTIVE_BUFFER_CAPACITY = 8;
847
+ export function resolveSpanBufferCapacity(explicitCapacity, adaptiveCapacity) {
848
+ if (explicitCapacity === undefined)
849
+ return Math.max(MIN_ADAPTIVE_BUFFER_CAPACITY, adaptiveCapacity);
850
+ if (!Number.isSafeInteger(explicitCapacity) || explicitCapacity < 2) {
851
+ throw new RangeError('Explicit span buffer capacity must be a safe integer of at least 2');
852
+ }
853
+ return explicitCapacity;
854
+ }
373
855
  //#region smoo/lmao!n/spanbuffer-layout.create-root
374
- export function createSpanBuffer(schema, traceRoot, opMetadata, capacity) {
375
- const SpanBufferClass = getSpanBufferClass(schema);
856
+ export function createSpanBuffer(schema, traceRoot, opMetadata, capacity, plannedClass) {
857
+ const metadataPlan = opMetadata._physicalLayoutPlan;
858
+ const metadataSpanBufferClass = metadataPlan?.SpanBufferClass;
859
+ if (metadataSpanBufferClass !== undefined && !isSpanBufferConstructorForSchema(metadataSpanBufferClass, schema)) {
860
+ throw new TypeError('Planned SpanBuffer class does not match schema');
861
+ }
862
+ const plannedSpanBufferClass = plannedClass ?? metadataSpanBufferClass;
863
+ const SpanBufferClass = plannedSpanBufferClass ?? getSpanBufferClass(schema);
376
864
  const stats = SpanBufferClass.stats;
377
- // Use provided capacity or default from class stats, enforce minimum
378
- const actualCapacity = Math.max(MIN_CAPACITY, capacity ?? stats.capacity);
865
+ // Compiler-planned capacities are validated when the runtime hint is decoded. Keep direct external calls strict.
866
+ const actualCapacity = plannedSpanBufferClass === undefined
867
+ ? resolveSpanBufferCapacity(capacity, stats.capacity)
868
+ : (capacity ?? Math.max(MIN_ADAPTIVE_BUFFER_CAPACITY, stats.capacity));
379
869
  // Track non-chained buffer creation for capacity tuning
380
870
  stats.spansCreated++;
381
- // Create root buffer (no parent)
382
- // Root spans use same metadata for both callsite and op (no distinction at root)
383
- return new SpanBufferClass(actualCapacity, stats, undefined, // no parent
384
- false, // not chained
385
- opMetadata, // callsiteMetadata for row 0
386
- opMetadata, // opMetadata for rows 1+ (same as callsite for root)
387
- traceRoot);
871
+ // Create root buffer (no parent), then register its stable logical node.
872
+ const buffer = new SpanBufferClass(actualCapacity, stats, undefined, false, opMetadata, opMetadata, traceRoot, metadataPlan?.vocabularyGeneration ?? getVocabularyGeneration());
873
+ traceRoot._topology.registerRoot(buffer);
874
+ return buffer;
388
875
  }
389
876
  //#endregion smoo/lmao!n/spanbuffer-layout.create-root
390
877
  /**
@@ -407,9 +894,11 @@ export function createOverflowBuffer(buffer) {
407
894
  // Pass buffer as parent - used for identity sharing; _parent set to buffer._parent in constructor
408
895
  const nextBuffer = new SpanBufferClass(capacity, stats, buffer, // Used for identity sharing, _parent set to buffer._parent in constructor
409
896
  true, // isChained
410
- buffer._callsiteMetadata, buffer._opMetadata, buffer._traceRoot);
897
+ buffer._callsiteMetadata, buffer._opMetadata, buffer._traceRoot, // traceRoot from parent
898
+ buffer._vocabularyGeneration);
411
899
  // Link current buffer to next
412
900
  buffer._overflow = nextBuffer;
901
+ buffer._traceRoot._topology.adoptOverflow(buffer, nextBuffer);
413
902
  return nextBuffer;
414
903
  }
415
904
  //#endregion smoo/lmao!n/spanbuffer-layout.create-overflow
@@ -432,7 +921,8 @@ export function createOverflowBuffer(buffer) {
432
921
  //#region smoo/lmao!n/spanbuffer-layout.create-child
433
922
  export function createChildSpanBuffer(parentBuffer, SpanBufferClass, callsiteMetadata, opMetadata, capacity) {
434
923
  const stats = SpanBufferClass.stats;
435
- const actualCapacity = capacity ?? stats.capacity;
924
+ // Child capacities arrive through a validated callsite plan; preserve exact values including 2..7.
925
+ const actualCapacity = capacity ?? Math.max(MIN_ADAPTIVE_BUFFER_CAPACITY, stats.capacity);
436
926
  // Track non-chained buffer creation for capacity tuning
437
927
  stats.spansCreated++;
438
928
  // Create child buffer with parent reference
@@ -440,7 +930,9 @@ export function createChildSpanBuffer(parentBuffer, SpanBufferClass, callsiteMet
440
930
  false, // not chained
441
931
  callsiteMetadata, // callsiteMetadata - CALLER's op metadata (for row 0)
442
932
  opMetadata, // opMetadata - EXECUTING op metadata (for rows 1+)
443
- parentBuffer._traceRoot);
933
+ parentBuffer._traceRoot, // traceRoot from parent
934
+ opMetadata._physicalLayoutPlan?.vocabularyGeneration ?? getVocabularyGeneration());
935
+ parentBuffer._traceRoot._topology.registerChild(parentBuffer, childBuffer);
444
936
  return childBuffer;
445
937
  }
446
938
  //#endregion smoo/lmao!n/spanbuffer-layout.create-child