@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
@@ -11,6 +11,15 @@
11
11
  */
12
12
  import { getSchemaType } from '@smoothbricks/arrow-builder';
13
13
  import { checkCapacityTuning } from '../capacityTuning.js';
14
+ import { getVocabularyGeneration } from '../vocabularyRegistry.js';
15
+ import { WASM_NO_LAYOUT_OFFSET, WASM_SPAN_IDENTITY_CHILD, WASM_SPAN_IDENTITY_ROOT, } from './wasmAllocator.js';
16
+ import { getWasmPhysicalLayout, } from './wasmPhysicalLayout.js';
17
+ const EMPTY_EAGER_COLUMNS = Object.freeze({
18
+ names: Object.freeze([]),
19
+ words: Object.freeze([]),
20
+ key: '',
21
+ });
22
+ let nextWasmBufferGeneration = 0;
14
23
  function getFieldEager(value) {
15
24
  return typeof value === 'object' && value !== null && Reflect.get(value, '__eager') === true;
16
25
  }
@@ -21,23 +30,13 @@ function getFieldEnumValues(value) {
21
30
  const enumValues = Reflect.get(value, '__enum_values');
22
31
  return Array.isArray(enumValues) ? enumValues : undefined;
23
32
  }
24
- function isColumnValueType(value) {
25
- return value === undefined || Array.isArray(value) || ArrayBuffer.isView(value);
26
- }
27
- function getFreeMethod(sizeClass) {
28
- switch (sizeClass) {
29
- case '1b':
30
- return 'free1B';
31
- case '4b':
32
- return 'free4B';
33
- case '8b':
34
- return 'free8B';
35
- }
36
- }
37
- function isWasmSpanBufferConstructor(value) {
33
+ function isWasmSpanBufferConstructor(value, schema, messageLayoutFamily, messagePhysicalLayout) {
38
34
  return (typeof value === 'function' &&
39
35
  typeof Reflect.get(value, 'schema') === 'object' &&
40
36
  Reflect.get(value, 'schema') !== null &&
37
+ (schema === undefined || Reflect.get(value, 'schema') === schema) &&
38
+ (messageLayoutFamily === undefined || Reflect.get(value, 'messageLayoutFamily') === messageLayoutFamily) &&
39
+ (messagePhysicalLayout === undefined || Reflect.get(value, 'messagePhysicalLayout') === messagePhysicalLayout) &&
41
40
  typeof Reflect.get(value, 'stats') === 'object' &&
42
41
  Reflect.get(value, 'stats') !== null);
43
42
  }
@@ -45,7 +44,7 @@ export function isWasmSpanBufferInstance(value) {
45
44
  return typeof value === 'object' && value !== null && typeof Reflect.get(value, '_systemPtr') === 'number';
46
45
  }
47
46
  function getWasmSpanBufferConstructor(instance) {
48
- if (!isWasmSpanBufferConstructor(instance.constructor)) {
47
+ if (!isWasmSpanBufferConstructor(instance.constructor, instance._logSchema)) {
49
48
  throw new Error('Expected generated WasmSpanBuffer constructor');
50
49
  }
51
50
  return instance.constructor;
@@ -57,14 +56,15 @@ function isWasmSpanBufferFactory(value) {
57
56
  * Build column metadata array from schema.
58
57
  * Maps each schema field to its storage characteristics.
59
58
  */
60
- function buildColumnMeta(schema) {
59
+ function buildColumnMeta(schema, eagerColumns) {
61
60
  const result = [];
62
61
  const fields = schema.fields;
62
+ const preallocatedColumns = new Set(eagerColumns.names);
63
63
  let columnIndex = 0;
64
64
  for (const name of schema._columnNames) {
65
65
  const field = fields[name];
66
66
  const schemaType = getSchemaType(field);
67
- const isEager = getFieldEager(field);
67
+ const isSchemaEager = getFieldEager(field);
68
68
  const enumValues = getFieldEnumValues(field);
69
69
  let sizeClass;
70
70
  switch (schemaType) {
@@ -88,7 +88,8 @@ function buildColumnMeta(schema) {
88
88
  sizeClass,
89
89
  schemaType: schemaType ?? 'unknown',
90
90
  columnIndex,
91
- isEager,
91
+ isSchemaEager,
92
+ isPreallocated: !isSchemaEager && preallocatedColumns.has(name),
92
93
  enumValues,
93
94
  });
94
95
  columnIndex++;
@@ -98,45 +99,42 @@ function buildColumnMeta(schema) {
98
99
  // =============================================================================
99
100
  // Common WasmSpanBuffer Methods (shared via prototype)
100
101
  // =============================================================================
101
- /**
102
- * Get timestamp column view from WASM memory.
103
- * Assigned to prototype after class generation.
104
- */
102
+ function wasmEnsureViews() {
103
+ assertWasmBufferLive(this);
104
+ const memoryVersion = this._allocator.refreshViews();
105
+ if (memoryVersion !== this._viewVersion)
106
+ this._refreshViews(memoryVersion);
107
+ }
105
108
  function wasmGetTimestamp() {
106
- return new BigInt64Array(this._allocator.memory.buffer, this._systemPtr, this._capacity);
109
+ wasmEnsureViews.call(this);
110
+ return this._timestampView;
107
111
  }
108
- /**
109
- * Get entry_type column view from WASM memory.
110
- * Assigned to prototype after class generation.
111
- */
112
112
  function wasmGetEntryType() {
113
- return new Uint8Array(this._allocator.memory.buffer, this._systemPtr + this._capacity * 8, this._capacity);
113
+ wasmEnsureViews.call(this);
114
+ return this._entryTypeView;
115
+ }
116
+ function assertWasmBufferLive(buffer) {
117
+ if (buffer._descriptor.state !== 'live') {
118
+ const generation = buffer._descriptor.generation;
119
+ throw new Error(`Cannot access released WASM buffer generation ${generation}; generation ${generation} has been released`);
120
+ }
114
121
  }
115
- /**
116
- * Get writeIndex from WASM identity block.
117
- */
118
122
  function wasmGetWriteIndex() {
119
- return this._allocator.readWriteIndex(this._identityPtr);
123
+ wasmEnsureViews.call(this);
124
+ return this._identityOwner ? this._identityData.getUint32(0, true) : this._overflowWriteIndex;
120
125
  }
121
- /**
122
- * Set writeIndex in WASM identity block.
123
- */
124
126
  function wasmSetWriteIndex(value) {
125
- new DataView(this._allocator.memory.buffer).setUint32(this._identityPtr, value, true);
127
+ wasmEnsureViews.call(this);
128
+ if (this._identityOwner) {
129
+ this._identityData.setUint32(0, value, true);
130
+ }
131
+ else {
132
+ this._overflowWriteIndex = value;
133
+ }
126
134
  }
127
- /**
128
- * Get trace_id from WASM identity block.
129
- */
130
135
  function wasmGetTraceId() {
131
- const len = this._allocator.readIdentityTraceIdLen(this._identityPtr);
132
- if (len === 0) {
133
- let p = this._parent;
134
- while (p?._parent)
135
- p = p._parent;
136
- return p ? p.trace_id : '';
137
- }
138
- const traceIdPtr = this._allocator.getIdentityTraceIdPtr(this._identityPtr);
139
- return new TextDecoder().decode(new Uint8Array(this._allocator.memory.buffer, traceIdPtr, len));
136
+ assertWasmBufferLive(this);
137
+ return this._traceRoot.trace_id;
140
138
  }
141
139
  function wasmGetSpanStartTime() {
142
140
  return this.timestamp[0];
@@ -163,15 +161,12 @@ function wasmGetLastLoggedTime() {
163
161
  * Get thread_id from WASM identity block.
164
162
  */
165
163
  function wasmGetThreadId() {
166
- const high = this._allocator.getThreadIdHigh();
167
- const low = this._allocator.getThreadIdLow();
168
- return (BigInt(high) << 32n) | BigInt(low);
164
+ assertWasmBufferLive(this);
165
+ return this._threadId;
169
166
  }
170
- /**
171
- * Get span_id from WASM identity block.
172
- */
173
167
  function wasmGetSpanId() {
174
- return this._allocator.readIdentitySpanId(this._identityPtr);
168
+ assertWasmBufferLive(this);
169
+ return this._spanId;
175
170
  }
176
171
  /**
177
172
  * Get parent_thread_id.
@@ -191,93 +186,102 @@ function wasmGetParentSpanId() {
191
186
  function wasmGetHasParent() {
192
187
  return this._parent !== null;
193
188
  }
194
- /**
195
- * Message column setter.
196
- */
197
- function wasmMessage(idx, value) {
189
+ function wasmRawMessage(idx, value) {
190
+ assertWasmBufferLive(this);
198
191
  this._message[idx] = value;
199
192
  return this;
200
193
  }
194
+ function wasmStaticMessage(idx, value) {
195
+ assertWasmBufferLive(this);
196
+ if (idx === 0)
197
+ this._spanName = value;
198
+ else if (idx === 1)
199
+ this._terminalMessage = value;
200
+ else
201
+ throw new RangeError('Static-only buffers only accept raw system messages at rows 0 and 1');
202
+ return this;
203
+ }
201
204
  /**
202
205
  * Get message column values.
203
206
  */
204
207
  function wasmGetMessageValues() {
208
+ assertWasmBufferLive(this);
205
209
  return this._message;
206
210
  }
207
- /**
208
- * Get message column nulls (always undefined for eager column).
209
- */
210
- function wasmGetMessageNulls() {
211
- return undefined;
211
+ function wasmGetMessageLayoutFamily() {
212
+ return getWasmSpanBufferConstructor(this).messageLayoutFamily;
212
213
  }
213
- /**
214
- * Free all WASM memory for this buffer.
215
- */
214
+ function wasmGetMessagePhysicalLayout() {
215
+ return getWasmSpanBufferConstructor(this).messagePhysicalLayout;
216
+ }
217
+ /** Free the one owned root/child/overflow superblock exactly once. */
216
218
  function wasmFree() {
217
- // Free identity block
218
- this._allocator.freeIdentity(this._identityPtr);
219
- // Free system block
220
- this._allocator.freeSpanSystem(this._systemPtr);
221
- // Free column blocks
222
- const columnMeta = buildColumnMeta(this._logSchema);
223
- for (const col of columnMeta) {
224
- if (col.sizeClass !== 'string' && this._columnPtrs[col.columnIndex] >= 0) {
225
- const freeMethod = getFreeMethod(col.sizeClass);
226
- this._allocator[freeMethod](this._columnPtrs[col.columnIndex]);
227
- }
228
- }
219
+ if (this._descriptor.state === 'freed')
220
+ return;
221
+ if (this._viewVersion !== 0)
222
+ this._sealStats();
223
+ this._allocator.freeSpanSuperblock(this._allocationPtr, this._allocationByteLength);
224
+ this._descriptor.state = 'freed';
229
225
  }
230
226
  /**
231
227
  * Check if column is allocated.
232
228
  */
233
229
  function wasmIsColumnAllocated(columnIndex) {
234
- return this._columnPtrs[columnIndex] >= 0;
230
+ assertWasmBufferLive(this);
231
+ wasmEnsureViews.call(this);
232
+ return this._columnPtrs[columnIndex] >= 0 || this._getWasmColumnValue(columnIndex) !== undefined;
235
233
  }
236
- /**
237
- * Get column values if allocated.
238
- */
234
+ /** Get a canonical column value view or JS sidecar without accessor reflection. */
239
235
  function wasmGetColumnIfAllocated(columnName) {
236
+ assertWasmBufferLive(this);
240
237
  const idx = this._logSchema._columnNames.indexOf(columnName);
241
238
  if (idx === -1)
242
239
  return undefined;
243
- const getter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), `${columnName}_values`);
244
- if (getter?.get) {
245
- const value = getter.get.call(this);
246
- return isColumnValueType(value) ? value : undefined;
247
- }
248
- return undefined;
240
+ wasmEnsureViews.call(this);
241
+ return this._getWasmColumnValue(idx);
249
242
  }
250
- /**
251
- * Get column nulls if allocated.
252
- */
243
+ /** Get a canonical column null-bitmap view without accessor reflection. */
253
244
  function wasmGetNullsIfAllocated(columnName) {
254
- const getter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), `${columnName}_nulls`);
255
- if (getter?.get) {
256
- return getter.get.call(this);
257
- }
258
- return undefined;
245
+ assertWasmBufferLive(this);
246
+ const idx = this._logSchema._columnNames.indexOf(columnName);
247
+ if (idx === -1)
248
+ return undefined;
249
+ wasmEnsureViews.call(this);
250
+ return this._getWasmColumnNulls(idx);
259
251
  }
260
- /**
261
- * Get system ArrayBuffer for compatibility with AnySpanBuffer.
262
- * WASM uses shared memory, so this returns the entire WASM memory buffer.
263
- */
252
+ /** Get the current WASM memory backing store. */
264
253
  function wasmGetSystem() {
254
+ wasmEnsureViews.call(this);
265
255
  return this._allocator.memory.buffer;
266
256
  }
267
- /**
268
- * Get identity Uint8Array for compatibility with AnySpanBuffer.
269
- * Returns a view of the identity block (48 bytes) in WASM memory.
270
- */
257
+ /** Get the canonical identity view for the current memory version. */
271
258
  function wasmGetIdentity() {
272
- // Identity block is 48 bytes: writeIndex(4) + reserved(4) + span_id(4) + trace_id_len(1) + trace_id(up to 35)
273
- return new Uint8Array(this._allocator.memory.buffer, this._identityPtr, 48);
259
+ wasmEnsureViews.call(this);
260
+ return this._identityView;
261
+ }
262
+ function wasmSealStats() {
263
+ if (this._statsSealed)
264
+ return;
265
+ const completedRows = this._writeIndex - this._statsReservedRows;
266
+ if (completedRows > 0)
267
+ getWasmSpanBufferConstructor(this).stats.totalWrites += completedRows;
268
+ this._statsSealed = true;
269
+ }
270
+ function wasmSealStatsChain() {
271
+ let current = this;
272
+ while (current) {
273
+ current._sealStats();
274
+ current = current._overflow;
275
+ }
274
276
  }
275
277
  /**
276
278
  * Get or create overflow buffer.
277
279
  */
278
280
  function wasmGetOrCreateOverflow() {
281
+ assertWasmBufferLive(this);
279
282
  if (this._overflow)
280
283
  return this._overflow;
284
+ this._sealStats();
281
285
  const tracer = this._traceRoot.tracer;
282
286
  tracer.onStatsWillResetFor(this);
283
287
  checkCapacityTuning(getWasmSpanBufferConstructor(this).stats);
@@ -313,63 +317,26 @@ function wasmInspect() {
313
317
  * Generate eager column initialization code for constructor.
314
318
  * Eager columns are pre-allocated, lazy columns start as undefined/-1.
315
319
  */
316
- function generateEagerColumnInit(columnMeta) {
320
+ function generateColumnInit(columnMeta) {
317
321
  const lines = [];
318
322
  for (const col of columnMeta) {
319
- if (col.name === 'message')
320
- continue; // Message handled separately
321
- if (col.sizeClass === 'string') {
322
- if (col.isEager) {
323
- lines.push(`this._${col.name}_values = new Array(this._capacity);`);
324
- }
325
- else {
326
- lines.push(`this._${col.name}_values = undefined;`);
327
- lines.push(`this._${col.name}_nulls = undefined;`);
328
- }
323
+ if (col.name === 'message' || col.sizeClass !== 'string')
324
+ continue;
325
+ if (col.isSchemaEager) {
326
+ lines.push(`this._${col.name}_values = new Array(this._capacity);`);
327
+ }
328
+ else if (col.isPreallocated) {
329
+ lines.push(`this._${col.name}_values = new Array(this._capacity);`);
330
+ lines.push(`this._${col.name}_nulls = new Uint8Array((this._capacity + 7) >>> 3);`);
329
331
  }
330
- else if (col.isEager) {
331
- lines.push(`this._columnPtrs[${col.columnIndex}] = this._allocator.alloc${col.sizeClass.toUpperCase()}();`);
332
+ else {
333
+ lines.push(`this._${col.name}_values = undefined;`);
334
+ lines.push(`this._${col.name}_nulls = undefined;`);
332
335
  }
333
336
  }
334
337
  return lines.join('\n ');
335
338
  }
336
- /**
337
- * Generate setter method for a numeric column (stored in WASM).
338
- * Calls WASM exports directly for hot path optimization.
339
- */
340
- function generateNumericSetter(col) {
341
- const allocMethod = `alloc${col.sizeClass.toUpperCase()}`;
342
- // Map to WASM export names
343
- const writeExportName = col.schemaType === 'number' || col.schemaType === 'bigUint64'
344
- ? 'write_col_f64'
345
- : col.sizeClass === '1b'
346
- ? 'write_col_u8'
347
- : col.sizeClass === '4b'
348
- ? 'write_col_u32'
349
- : 'write_col_f64';
350
- if (col.isEager) {
351
- // Eager: column is pre-allocated, just write value (call WASM export directly)
352
- return `${col.name}(idx, value) {
353
- const ptr = this._columnPtrs[${col.columnIndex}];
354
- this._allocator.exports.${writeExportName}(ptr, idx, value, this._capacity);
355
- return this;
356
- }`;
357
- }
358
- // Lazy: allocate on first write (call WASM export directly)
359
- return `${col.name}(idx, value) {
360
- let ptr = this._columnPtrs[${col.columnIndex}];
361
- if (ptr < 0) {
362
- ptr = this._allocator.${allocMethod}();
363
- this._columnPtrs[${col.columnIndex}] = ptr;
364
- }
365
- this._allocator.exports.${writeExportName}(ptr, idx, value, this._capacity);
366
- return this;
367
- }`;
368
- }
369
- /**
370
- * Generate getter for numeric column values (creates view on demand).
371
- */
372
- function generateNumericValuesGetter(col) {
339
+ function generateNumericViewBinding(col, layoutIndex) {
373
340
  const arrayType = col.schemaType === 'number'
374
341
  ? 'Float64Array'
375
342
  : col.schemaType === 'bigUint64'
@@ -379,59 +346,146 @@ function generateNumericValuesGetter(col) {
379
346
  : col.sizeClass === '4b'
380
347
  ? 'Uint32Array'
381
348
  : 'Float64Array';
382
- const bytesPerElement = col.sizeClass === '1b' ? 1 : col.sizeClass === '4b' ? 4 : 8;
383
- return `get ${col.name}_values() {
384
- const ptr = this._columnPtrs[${col.columnIndex}];
385
- if (ptr < 0) return ${col.isEager ? 'null' : 'undefined'};
386
- const nullBitmapSize = Math.ceil(this._capacity / 8);
387
- const valueOffset = ptr + nullBitmapSize;
388
- // Align offset for typed array
389
- const alignedOffset = (valueOffset + ${bytesPerElement - 1}) & ~${bytesPerElement - 1};
390
- return new ${arrayType}(
391
- this._allocator.memory.buffer,
392
- alignedOffset,
393
- this._capacity
394
- );
349
+ return `const column = this._layout.columns[${layoutIndex}];
350
+ const familyPtr = this._familyPtrs[column.family];
351
+ this._${col.name}_nulls = new Uint8Array(memory, familyPtr + column.nullOffset, column.nullByteLength);
352
+ this._${col.name}_values = new ${arrayType}(memory, familyPtr + column.valueOffset, this._capacity);
353
+ this._columnPtrs[${col.columnIndex}] = familyPtr + column.nullOffset;`;
354
+ }
355
+ function generateEnsureNumericView(col, layoutIndex) {
356
+ if (col.isSchemaEager || col.isPreallocated)
357
+ return '';
358
+ return `if (this._columnPtrs[${col.columnIndex}] === -1) {
359
+ const memory = this._allocator.memory.buffer;
360
+ ${generateNumericViewBinding(col, layoutIndex)}
361
+ }`;
362
+ }
363
+ function generateNumericSetter(col, layoutIndex) {
364
+ const ensureView = generateEnsureNumericView(col, layoutIndex);
365
+ const validity = col.isSchemaEager
366
+ ? `this._${col.name}_values[idx] = value;`
367
+ : `if (value == null) {
368
+ this._${col.name}_nulls[idx >>> 3] &= ~(1 << (idx & 7));
369
+ } else {
370
+ this._${col.name}_nulls[idx >>> 3] |= 1 << (idx & 7);
371
+ this._${col.name}_values[idx] = value;
372
+ }`;
373
+ return `${col.name}(idx, value) {
374
+ this._ensureWasmViews();
375
+ ${ensureView}
376
+ ${validity}
377
+ return this;
395
378
  }`;
396
379
  }
397
- /**
398
- * Generate getter for numeric column nulls bitmap.
399
- */
400
- function generateNumericNullsGetter(col) {
401
- if (col.isEager) {
402
- // Eager columns don't have null bitmaps
403
- return `get ${col.name}_nulls() {
404
- return undefined;
380
+ function generateNumericValuesGetter(col, layoutIndex) {
381
+ return `get ${col.name}_values() {
382
+ this._ensureWasmViews();
383
+ ${generateEnsureNumericView(col, layoutIndex)}
384
+ return this._${col.name}_values;
405
385
  }`;
386
+ }
387
+ function generateNumericNullsGetter(col, layoutIndex) {
388
+ if (col.isSchemaEager) {
389
+ return `get ${col.name}_nulls() { return undefined; }`;
406
390
  }
407
391
  return `get ${col.name}_nulls() {
408
- const ptr = this._columnPtrs[${col.columnIndex}];
409
- if (ptr < 0) return undefined;
410
- const nullBitmapSize = Math.ceil(this._capacity / 8);
411
- return new Uint8Array(
412
- this._allocator.memory.buffer,
413
- ptr,
414
- nullBitmapSize
415
- );
392
+ this._ensureWasmViews();
393
+ ${generateEnsureNumericView(col, layoutIndex)}
394
+ return this._${col.name}_nulls;
416
395
  }`;
417
396
  }
397
+ function generateViewRefresh(columnMeta, messageLayoutFamily, messagePhysicalLayout) {
398
+ const lines = [
399
+ 'const memory = this._allocator.memory.buffer;',
400
+ 'this._timestampView = new BigInt64Array(memory, this._systemPtr, this._capacity);',
401
+ ];
402
+ if (messagePhysicalLayout === 'packed') {
403
+ lines.push('this._rowHeaders = new Uint32Array(memory, this._systemPtr + this._layout.system.rowHeaderOffset, this._capacity);');
404
+ }
405
+ else {
406
+ lines.push('this._entryTypeView = new Uint8Array(memory, this._systemPtr + this._layout.system.entryTypeOffset, this._capacity);');
407
+ if (messageLayoutFamily !== 'dynamic-only') {
408
+ if (messagePhysicalLayout === 'current') {
409
+ lines.push('this._messageIds = new Uint16Array(memory, this._systemPtr + this._layout.system.messageIdOffset, this._capacity);');
410
+ }
411
+ else {
412
+ lines.push('this._logHeaders = new Uint32Array(memory, this._systemPtr + this._layout.system.messageDenseIndexOffset, this._capacity);');
413
+ }
414
+ }
415
+ }
416
+ lines.push(`if (this._identityOwner) {
417
+ this._identityView = new Uint8Array(memory, this._identityPtr, 128);
418
+ this._identityData = new DataView(memory, this._identityPtr, 128);
419
+ } else {
420
+ this._identitySource._ensureWasmViews();
421
+ this._identityView = this._identitySource._identityView;
422
+ this._identityData = this._identitySource._identityData;
423
+ }`);
424
+ let layoutIndex = 0;
425
+ for (const col of columnMeta) {
426
+ if (col.sizeClass === 'string' || col.name === 'message')
427
+ continue;
428
+ const binding = generateNumericViewBinding(col, layoutIndex);
429
+ if (col.isSchemaEager || col.isPreallocated) {
430
+ lines.push(`{ ${binding} }`);
431
+ }
432
+ else {
433
+ lines.push(`if (this._columnPtrs[${col.columnIndex}] !== -1) { ${binding} }`);
434
+ }
435
+ layoutIndex++;
436
+ }
437
+ lines.push('this._viewVersion = version;', 'this._descriptor.memoryVersion = version;');
438
+ return lines.join('\n ');
439
+ }
440
+ function generateColumnLookup(columnMeta, nulls) {
441
+ const cases = [];
442
+ for (const col of columnMeta) {
443
+ if (col.name === 'message')
444
+ continue;
445
+ if (nulls && col.isSchemaEager)
446
+ cases.push(`case ${col.columnIndex}: return undefined;`);
447
+ else {
448
+ const property = nulls ? `_${col.name}_nulls` : `_${col.name}_values`;
449
+ cases.push(`case ${col.columnIndex}: return this.${property};`);
450
+ }
451
+ }
452
+ return `switch (columnIndex) { ${cases.join(' ')} default: return undefined; }`;
453
+ }
454
+ function generateEnsureStringStorage(col) {
455
+ if (col.isSchemaEager || col.isPreallocated)
456
+ return '';
457
+ return `if (this._${col.name}_values === undefined) {
458
+ this._${col.name}_values = new Array(this._capacity);
459
+ this._${col.name}_nulls = new Uint8Array((this._capacity + 7) >>> 3);
460
+ }`;
461
+ }
418
462
  /**
419
463
  * Generate setter method for a string column (stored in JS).
420
464
  */
421
465
  function generateStringSetter(col) {
422
- if (col.isEager) {
466
+ const ensureStorage = generateEnsureStringStorage(col);
467
+ if (col.isSchemaEager) {
423
468
  return `${col.name}(idx, value) {
469
+ if (this._descriptor.state !== 'live') throw new Error('Cannot write a released WASM buffer');
424
470
  this._${col.name}_values[idx] = value;
425
471
  return this;
472
+ }`;
473
+ }
474
+ if (col.isPreallocated) {
475
+ return `${col.name}(idx, value) {
476
+ if (this._descriptor.state !== 'live') throw new Error('Cannot write a released WASM buffer');
477
+ if (value == null) this._${col.name}_nulls[idx >>> 3] &= ~(1 << (idx & 7));
478
+ else {
479
+ this._${col.name}_values[idx] = value;
480
+ this._${col.name}_nulls[idx >>> 3] |= 1 << (idx & 7);
481
+ }
482
+ return this;
426
483
  }`;
427
484
  }
428
485
  // Lazy string column: allocate arrays on first write
429
486
  return `${col.name}(idx, value) {
430
- if (this._${col.name}_values === undefined) {
431
- this._${col.name}_values = new Array(this._capacity);
432
- const nullBitmapSize = Math.ceil(this._capacity / 8);
433
- this._${col.name}_nulls = new Uint8Array(nullBitmapSize);
434
- }
487
+ if (this._descriptor.state !== 'live') throw new Error('Cannot write a released WASM buffer');
488
+ ${ensureStorage}
435
489
  if (value == null) {
436
490
  // Clear validity bit
437
491
  this._${col.name}_nulls[idx >>> 3] &= ~(1 << (idx & 7));
@@ -447,12 +501,10 @@ function generateStringSetter(col) {
447
501
  * Generate getter for string column values.
448
502
  */
449
503
  function generateStringValuesGetter(col) {
450
- if (col.isEager) {
451
- return `get ${col.name}_values() {
452
- return this._${col.name}_values;
453
- }`;
454
- }
504
+ const ensureStorage = generateEnsureStringStorage(col);
455
505
  return `get ${col.name}_values() {
506
+ if (this._descriptor.state !== 'live') throw new Error('Cannot read a released WASM buffer');
507
+ ${ensureStorage}
456
508
  return this._${col.name}_values;
457
509
  }`;
458
510
  }
@@ -460,12 +512,15 @@ function generateStringValuesGetter(col) {
460
512
  * Generate getter for string column nulls.
461
513
  */
462
514
  function generateStringNullsGetter(col) {
463
- if (col.isEager) {
515
+ if (col.isSchemaEager) {
464
516
  return `get ${col.name}_nulls() {
465
517
  return undefined;
466
518
  }`;
467
519
  }
520
+ const ensureStorage = generateEnsureStringStorage(col);
468
521
  return `get ${col.name}_nulls() {
522
+ if (this._descriptor.state !== 'live') throw new Error('Cannot read a released WASM buffer');
523
+ ${ensureStorage}
469
524
  return this._${col.name}_nulls;
470
525
  }`;
471
526
  }
@@ -475,20 +530,20 @@ function generateStringNullsGetter(col) {
475
530
  */
476
531
  function generateColumnMethods(columnMeta) {
477
532
  const methods = [];
533
+ let layoutIndex = 0;
478
534
  for (const col of columnMeta) {
479
- // Skip 'message' - handled specially by generateMessageMethods()
480
- if (col.name === 'message') {
535
+ if (col.name === 'message')
481
536
  continue;
482
- }
483
537
  if (col.sizeClass === 'string') {
484
538
  methods.push(generateStringSetter(col));
485
539
  methods.push(generateStringValuesGetter(col));
486
540
  methods.push(generateStringNullsGetter(col));
487
541
  }
488
542
  else {
489
- methods.push(generateNumericSetter(col));
490
- methods.push(generateNumericValuesGetter(col));
491
- methods.push(generateNumericNullsGetter(col));
543
+ methods.push(generateNumericSetter(col, layoutIndex));
544
+ methods.push(generateNumericValuesGetter(col, layoutIndex));
545
+ methods.push(generateNumericNullsGetter(col, layoutIndex));
546
+ layoutIndex++;
492
547
  }
493
548
  }
494
549
  return methods.join('\n\n ');
@@ -496,10 +551,7 @@ function generateColumnMethods(columnMeta) {
496
551
  // =============================================================================
497
552
  // Class Cache and Generation
498
553
  // =============================================================================
499
- /**
500
- * Cache for generated WASM SpanBuffer classes.
501
- * Key is the schema object reference (WeakMap for GC).
502
- */
554
+ /** Cache for generated WASM SpanBuffer classes, partitioned by schema and message family. */
503
555
  const wasmSpanBufferClassCache = new WeakMap();
504
556
  /**
505
557
  * Generate a WASM SpanBuffer class for the given schema.
@@ -509,59 +561,132 @@ const wasmSpanBufferClassCache = new WeakMap();
509
561
  * @param schema - LogSchema defining the buffer structure
510
562
  * @returns WasmSpanBufferConstructor for creating buffer instances
511
563
  */
512
- export function getWasmSpanBufferClass(schema) {
513
- const cached = wasmSpanBufferClassCache.get(schema);
514
- if (cached) {
564
+ export function getWasmSpanBufferClass(schema, messageLayoutFamily = 'mixed', messagePhysicalLayout = 'current', eagerColumns = EMPTY_EAGER_COLUMNS) {
565
+ const cacheKey = `${messageLayoutFamily}:${messagePhysicalLayout}:${eagerColumns.key}`;
566
+ let familyClasses = wasmSpanBufferClassCache.get(schema);
567
+ const cached = familyClasses?.get(cacheKey);
568
+ if (cached !== undefined && isWasmSpanBufferConstructor(cached, schema, messageLayoutFamily, messagePhysicalLayout))
515
569
  return cached;
516
- }
517
- // Pre-compute column metadata
518
- const columnMeta = buildColumnMeta(schema);
570
+ const columnMeta = buildColumnMeta(schema, eagerColumns);
519
571
  // Generate ONLY schema-specific code (constructor + column methods)
520
572
  const classCode = `
521
573
  class WasmSpanBuffer {
522
574
  constructor(opts) {
523
- // Store allocator and capacity
524
575
  this._allocator = opts.allocator;
525
576
  this._capacity = opts.capacity;
526
577
  this._logSchema = opts.logSchema;
578
+ this._parent = opts._parent ?? null;
579
+ this._nodeIndex = 4294967295;
580
+ this._topologyGeneration = 0;
581
+ this._overflow = null;
582
+ this._overflowWriteIndex = 0;
583
+ this._layout = opts._layout;
584
+ if (this._layout.messageLayoutFamily !== '${messageLayoutFamily}') {
585
+ throw new TypeError('WASM layout descriptor does not match its generated message family');
586
+ }
587
+ if (this._layout.messagePhysicalLayout !== '${messagePhysicalLayout}') {
588
+ throw new TypeError('WASM layout descriptor does not match its generated physical layout');
589
+ }
527
590
 
528
- // Allocate identity block from WASM (root has trace_id, child does not)
529
- if (opts.trace_id) {
530
- const traceIdBytes = new TextEncoder().encode(opts.trace_id);
531
- const packed = opts.allocator.allocIdentityRootForJsWrite(traceIdBytes.length);
532
- this._identityPtr = Number(packed >> 32n);
533
- const traceIdOffset = Number(packed & 0xFFFFFFFFn);
534
- new Uint8Array(opts.allocator.memory.buffer).set(traceIdBytes, traceIdOffset);
591
+ this._traceRoot = opts._traceRoot;
592
+ this._scopeValues = opts._scopeValues;
593
+ this._opMetadata = opts._opMetadata;
594
+ this._callsiteMetadata = opts._callsiteMetadata;
595
+ this._vocabularyGeneration = opts._vocabularyGeneration;
596
+ this._statsSealed = false;
597
+ this._statsReservedRows = 2;
598
+ this._columnPtrs = new Int32Array(${columnMeta.length}).fill(-1);
599
+ ${messageLayoutFamily === 'static-only'
600
+ ? `this._spanName = undefined;
601
+ this._terminalMessage = undefined;`
602
+ : messageLayoutFamily === 'dynamic-only'
603
+ ? `this._spanName = undefined;
604
+ this._message = new Array(opts.capacity);`
605
+ : 'this._message = new Array(opts.capacity);'}
606
+ ${generateColumnInit(columnMeta)}
607
+
608
+ const identityMode = opts._identityMode ?? 'root';
609
+ this._identityOwner = identityMode !== 'overflow';
610
+ this._identitySource = identityMode === 'overflow' ? opts._identitySource : undefined;
611
+ const superblock = this._identityOwner ? this._layout.spanSuperblock : this._layout.overflowSuperblock;
612
+ this._allocationByteLength = superblock.byteLength;
613
+ if (identityMode === 'overflow') {
614
+ if (!this._identitySource) throw new Error('Overflow buffer requires an identity owner');
615
+ this._allocationPtr = opts.allocator.createOverflowSpan(superblock.byteLength);
616
+ this._identityPtr = this._identitySource._identityPtr;
535
617
  } else {
536
- this._identityPtr = opts.allocator.allocIdentityChild();
618
+ const traceRootPtr = opts._traceRoot._traceRootPtr;
619
+ if (!Number.isInteger(traceRootPtr) || traceRootPtr <= 0) {
620
+ throw new TypeError('WASM span requires a live WasmTraceRoot');
621
+ }
622
+ const traceIdBytes = identityMode === 'root' ? opts._traceRoot._traceIdBytes : undefined;
623
+ this._allocationPtr = opts.allocator.createAndStartSpan(
624
+ identityMode === 'child' ? ${WASM_SPAN_IDENTITY_CHILD} : ${WASM_SPAN_IDENTITY_ROOT},
625
+ traceIdBytes?.length ?? 0,
626
+ superblock.byteLength,
627
+ superblock.systemOffset,
628
+ this._layout.system.entryTypeOffset ?? ${WASM_NO_LAYOUT_OFFSET},
629
+ this._layout.system.rowHeaderOffset ?? ${WASM_NO_LAYOUT_OFFSET},
630
+ traceRootPtr,
631
+ );
632
+ this._identityPtr = this._allocationPtr;
633
+ if (this._allocationPtr !== 0 && traceIdBytes !== undefined) {
634
+ opts.allocator.u8.set(traceIdBytes, this._identityPtr + 9);
635
+ }
537
636
  }
637
+ if (this._allocationPtr === 0) throw new Error('WASM span superblock allocation failed');
538
638
 
539
- // Allocate system block from WASM
540
- this._systemPtr = opts.allocator.allocSpanSystem();
639
+ this._systemPtr = this._allocationPtr + superblock.systemOffset;
640
+ const familyPtrs = { u8: 0, u32: 0, f64: 0 };
641
+ for (const family of ['u8', 'u32', 'f64']) {
642
+ const familyOffset = superblock.familyOffsets[family];
643
+ if (familyOffset !== 0) familyPtrs[family] = this._allocationPtr + familyOffset;
644
+ }
645
+ this._familyPtrs = Object.freeze(familyPtrs);
646
+ const allocatorWords = opts.allocator.u32;
647
+ this._threadId =
648
+ this._identitySource?.thread_id ?? ((BigInt(allocatorWords[7]) << 32n) | BigInt(allocatorWords[6]));
649
+ this._spanId = this._identitySource?.span_id ?? allocatorWords[(this._identityPtr + 4) >>> 2];
650
+ this._viewVersion = 0;
651
+ this._spanStartedAtAllocation = this._identityOwner;
541
652
 
542
- // Initialize column pointers as unallocated (-1)
543
- this._columnPtrs = new Int32Array(${columnMeta.length}).fill(-1);
653
+ this._descriptor = {
654
+ generation: opts._generation ?? 0,
655
+ kind: identityMode,
656
+ state: 'live',
657
+ layout: this._layout,
658
+ allocationPtr: this._allocationPtr,
659
+ allocationByteLength: this._allocationByteLength,
660
+ systemPtr: this._systemPtr,
661
+ familyPtrs: this._familyPtrs,
662
+ identityPtr: this._identityPtr,
663
+ ownsIdentity: this._identityOwner,
664
+ memoryVersion: 0,
665
+ parent: opts._parent?._descriptor,
666
+ };
544
667
 
545
- // Tree structure
546
- this._parent = null;
547
- this._children = [];
548
- this._overflow = null;
668
+ try {
669
+ this._refreshViews(this._allocator.refreshViews());
670
+ } catch (error) {
671
+ this.free();
672
+ throw error;
673
+ }
674
+ }
549
675
 
550
- // Assign context properties from opts
551
- this._traceRoot = opts._traceRoot;
552
- this._scopeValues = opts._scopeValues;
553
- this._opMetadata = opts._opMetadata;
554
- this._callsiteMetadata = opts._callsiteMetadata;
676
+ _refreshViews(version) {
677
+ ${generateViewRefresh(columnMeta, messageLayoutFamily, messagePhysicalLayout)}
678
+ }
555
679
 
556
- // Initialize message array
557
- this._message = new Array(opts.capacity);
680
+ _getWasmColumnValue(columnIndex) {
681
+ ${generateColumnLookup(columnMeta, false)}
682
+ }
558
683
 
559
- // Initialize eager columns
560
- ${generateEagerColumnInit(columnMeta)}
684
+ _getWasmColumnNulls(columnIndex) {
685
+ ${generateColumnLookup(columnMeta, true)}
561
686
  }
562
687
 
563
- // Schema-specific column methods (ONLY part that differs per schema)
564
688
  ${generateColumnMethods(columnMeta)}
689
+
565
690
  }
566
691
 
567
692
  return WasmSpanBuffer;
@@ -578,11 +703,13 @@ return WasmSpanBuffer;
578
703
  enumerable: true,
579
704
  configurable: true,
580
705
  });
581
- Object.defineProperty(WasmSpanBufferClass.prototype, 'entry_type', {
582
- get: wasmGetEntryType,
583
- enumerable: true,
584
- configurable: true,
585
- });
706
+ if (messagePhysicalLayout !== 'packed') {
707
+ Object.defineProperty(WasmSpanBufferClass.prototype, 'entry_type', {
708
+ get: wasmGetEntryType,
709
+ enumerable: true,
710
+ configurable: true,
711
+ });
712
+ }
586
713
  Object.defineProperty(WasmSpanBufferClass.prototype, '_writeIndex', {
587
714
  get: wasmGetWriteIndex,
588
715
  set: wasmSetWriteIndex,
@@ -619,13 +746,20 @@ return WasmSpanBuffer;
619
746
  enumerable: true,
620
747
  configurable: true,
621
748
  });
622
- Object.defineProperty(WasmSpanBufferClass.prototype, 'message_values', {
623
- get: wasmGetMessageValues,
749
+ if (messageLayoutFamily !== 'static-only') {
750
+ Object.defineProperty(WasmSpanBufferClass.prototype, 'message_values', {
751
+ get: wasmGetMessageValues,
752
+ enumerable: true,
753
+ configurable: true,
754
+ });
755
+ }
756
+ Object.defineProperty(WasmSpanBufferClass.prototype, '_messageLayoutFamily', {
757
+ get: wasmGetMessageLayoutFamily,
624
758
  enumerable: true,
625
759
  configurable: true,
626
760
  });
627
- Object.defineProperty(WasmSpanBufferClass.prototype, 'message_nulls', {
628
- get: wasmGetMessageNulls,
761
+ Object.defineProperty(WasmSpanBufferClass.prototype, '_messagePhysicalLayout', {
762
+ get: wasmGetMessagePhysicalLayout,
629
763
  enumerable: true,
630
764
  configurable: true,
631
765
  });
@@ -660,12 +794,15 @@ return WasmSpanBuffer;
660
794
  enumerable: true,
661
795
  configurable: true,
662
796
  });
663
- WasmSpanBufferClass.prototype.message = wasmMessage;
797
+ WasmSpanBufferClass.prototype._ensureWasmViews = wasmEnsureViews;
798
+ WasmSpanBufferClass.prototype.message = messageLayoutFamily === 'static-only' ? wasmStaticMessage : wasmRawMessage;
664
799
  WasmSpanBufferClass.prototype.free = wasmFree;
665
800
  WasmSpanBufferClass.prototype.isColumnAllocated = wasmIsColumnAllocated;
666
801
  WasmSpanBufferClass.prototype.getColumnIfAllocated = wasmGetColumnIfAllocated;
667
802
  WasmSpanBufferClass.prototype.getNullsIfAllocated = wasmGetNullsIfAllocated;
668
803
  WasmSpanBufferClass.prototype.getOrCreateOverflow = wasmGetOrCreateOverflow;
804
+ WasmSpanBufferClass.prototype._sealStats = wasmSealStats;
805
+ WasmSpanBufferClass.prototype._sealStatsChain = wasmSealStatsChain;
669
806
  WasmSpanBufferClass.prototype[Symbol.for('nodejs.util.inspect.custom')] = wasmInspect;
670
807
  // Add static schema property
671
808
  Object.defineProperty(WasmSpanBufferClass, 'schema', {
@@ -674,6 +811,24 @@ return WasmSpanBuffer;
674
811
  enumerable: true,
675
812
  configurable: false,
676
813
  });
814
+ Object.defineProperty(WasmSpanBufferClass, 'messageLayoutFamily', {
815
+ value: messageLayoutFamily,
816
+ writable: false,
817
+ enumerable: true,
818
+ configurable: false,
819
+ });
820
+ Object.defineProperty(WasmSpanBufferClass, 'messagePhysicalLayout', {
821
+ value: messagePhysicalLayout,
822
+ writable: false,
823
+ enumerable: true,
824
+ configurable: false,
825
+ });
826
+ Object.defineProperty(WasmSpanBufferClass, 'eagerColumns', {
827
+ value: eagerColumns,
828
+ writable: false,
829
+ enumerable: true,
830
+ configurable: false,
831
+ });
677
832
  // Add static stats property (required by SpanContext and arrow-builder's ColumnWriter)
678
833
  // This matches the structure in spanBuffer.ts
679
834
  // IMPORTANT: stats object itself must be writable so totalWrites++ and spansCreated++ can modify it
@@ -688,8 +843,12 @@ return WasmSpanBuffer;
688
843
  enumerable: true,
689
844
  configurable: true,
690
845
  });
691
- // Cache the class
692
- wasmSpanBufferClassCache.set(schema, WasmSpanBufferClass);
846
+ if (!isWasmSpanBufferConstructor(WasmSpanBufferClass, schema)) {
847
+ throw new Error('Generated WasmSpanBuffer constructor lost its schema identity');
848
+ }
849
+ familyClasses ??= new Map();
850
+ familyClasses.set(cacheKey, WasmSpanBufferClass);
851
+ wasmSpanBufferClassCache.set(schema, familyClasses);
693
852
  return WasmSpanBufferClass;
694
853
  }
695
854
  // =============================================================================
@@ -704,17 +863,24 @@ return WasmSpanBuffer;
704
863
  * @param _scopeValues - Scope values for this span
705
864
  * @param _opMetadata - Op metadata for attribution
706
865
  * @param _callsiteMetadata - Callsite metadata for attribution
707
- * @returns WasmSpanBufferInstance
866
+ * @returns Schema-specific WASM buffer instance
708
867
  */
709
868
  export function createWasmSpanBuffer(schema, opts, _traceRoot, _scopeValues, _opMetadata, _callsiteMetadata) {
710
- const WasmSpanBufferClass = getWasmSpanBufferClass(schema);
869
+ const messageLayoutFamily = opts.messageLayoutFamily ?? 'mixed';
870
+ const messagePhysicalLayout = opts.messagePhysicalLayout ?? 'current';
871
+ const eagerColumns = _opMetadata._physicalLayoutPlan?.eagerColumns ?? EMPTY_EAGER_COLUMNS;
872
+ const WasmSpanBufferClass = getWasmSpanBufferClass(schema, messageLayoutFamily, messagePhysicalLayout, eagerColumns);
711
873
  return new WasmSpanBufferClass({
712
874
  ...opts,
875
+ _identityMode: 'root',
876
+ _generation: ++nextWasmBufferGeneration,
877
+ _layout: getWasmPhysicalLayout(schema, opts.capacity, messageLayoutFamily, messagePhysicalLayout, eagerColumns),
713
878
  logSchema: schema,
714
879
  _traceRoot,
715
880
  _scopeValues,
716
881
  _opMetadata,
717
882
  _callsiteMetadata,
883
+ _vocabularyGeneration: _opMetadata._physicalLayoutPlan?.vocabularyGeneration ?? getVocabularyGeneration(),
718
884
  });
719
885
  }
720
886
  /**
@@ -729,25 +895,28 @@ export function createWasmSpanBuffer(schema, opts, _traceRoot, _scopeValues, _op
729
895
  * @param _scopeValues - Scope values for this span
730
896
  * @param _opMetadata - Op metadata for attribution
731
897
  * @param _callsiteMetadata - Callsite metadata for attribution
732
- * @returns WasmSpanBufferInstance linked to parent
898
+ * @returns Schema-specific child WASM buffer
733
899
  */
734
900
  export function createWasmChildSpanBuffer(parent, opts, _traceRoot, _scopeValues, _opMetadata, _callsiteMetadata) {
735
901
  // Use provided schema (for cross-library calls) or parent's schema
736
902
  const childSchema = opts.schema ?? parent._logSchema;
737
- const WasmSpanBufferClass = getWasmSpanBufferClass(childSchema);
903
+ const messageLayoutFamily = opts.messageLayoutFamily ?? parent._messageLayoutFamily;
904
+ const messagePhysicalLayout = opts.messagePhysicalLayout ?? parent._messagePhysicalLayout;
905
+ const eagerColumns = _opMetadata._physicalLayoutPlan?.eagerColumns ?? EMPTY_EAGER_COLUMNS;
906
+ const WasmSpanBufferClass = getWasmSpanBufferClass(childSchema, messageLayoutFamily, messagePhysicalLayout, eagerColumns);
738
907
  const child = new WasmSpanBufferClass({
739
908
  ...opts,
740
- logSchema: childSchema, // Use the child's schema (may differ from parent)
741
- trace_id: parent.trace_id,
742
- parent_thread_id: parent.thread_id,
743
- parent_span_id: parent.span_id,
909
+ logSchema: childSchema,
910
+ _identityMode: 'child',
911
+ _parent: parent,
912
+ _generation: ++nextWasmBufferGeneration,
913
+ _layout: getWasmPhysicalLayout(childSchema, opts.capacity, messageLayoutFamily, messagePhysicalLayout, eagerColumns),
744
914
  _traceRoot,
745
915
  _scopeValues,
746
916
  _opMetadata,
747
917
  _callsiteMetadata,
918
+ _vocabularyGeneration: _opMetadata._physicalLayoutPlan?.vocabularyGeneration ?? getVocabularyGeneration(),
748
919
  });
749
- // Link to parent (SpanContext will push to parent._children with possible RemappedBufferView wrapper)
750
- child._parent = parent;
751
920
  return child;
752
921
  }
753
922
  /**
@@ -758,27 +927,28 @@ export function createWasmChildSpanBuffer(parent, opts, _traceRoot, _scopeValues
758
927
  * @param _scopeValues - Scope values for this span
759
928
  * @param _opMetadata - Op metadata for attribution
760
929
  * @param _callsiteMetadata - Callsite metadata for attribution
761
- * @returns WasmSpanBufferInstance linked as overflow
930
+ * @returns Schema-specific overflow WASM buffer
762
931
  */
763
932
  export function createWasmOverflowBuffer(buffer, _traceRoot, _scopeValues, _opMetadata, _callsiteMetadata) {
764
- const WasmSpanBufferClass = getWasmSpanBufferClass(buffer._logSchema);
933
+ const WasmSpanBufferClass = getWasmSpanBufferConstructor(buffer);
765
934
  const overflow = new WasmSpanBufferClass({
766
935
  allocator: buffer._allocator,
767
936
  capacity: buffer._capacity,
768
- trace_id: buffer.trace_id,
769
- thread_id: buffer.thread_id,
770
- span_id: buffer.span_id,
771
- parent_thread_id: buffer.parent_thread_id,
772
- parent_span_id: buffer.parent_span_id,
773
937
  logSchema: buffer._logSchema,
774
938
  _traceRoot,
775
939
  _scopeValues,
776
940
  _opMetadata,
777
941
  _callsiteMetadata,
942
+ _vocabularyGeneration: buffer._vocabularyGeneration,
943
+ _identityMode: 'overflow',
944
+ _identitySource: buffer._identitySource ?? buffer,
945
+ _parent: buffer._parent,
946
+ _generation: ++nextWasmBufferGeneration,
947
+ _layout: buffer._layout,
778
948
  });
779
- // Link as overflow (not child - same logical span)
780
- overflow._parent = buffer._parent;
949
+ overflow._statsReservedRows = 0;
781
950
  buffer._overflow = overflow;
951
+ buffer._descriptor.overflow = overflow._descriptor;
782
952
  return overflow;
783
953
  }
784
954
  //#endregion smoo/lmao!n/wasm-mem.spanbuffer