@bldrs-ai/conway 1.536.1507 → 1.543.1513
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiled/examples/browser-bundled.cjs +39 -5
- package/compiled/examples/cli-bundled.cjs +197 -22
- package/compiled/examples/cli-step-bundled.cjs +39 -5
- package/compiled/examples/validator-bundled.cjs +39 -5
- package/compiled/src/compat/web-ifc/geometry_shard_coordination.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/geometry_shard_coordination.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/geometry_shard_coordination.test.js +236 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts +26 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api.js +33 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts +6 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.js +264 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts +116 -5
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.js +256 -85
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts +79 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/store_preview_channel.js +237 -14
- package/compiled/src/compat/web-ifc/store_preview_channel.test.js +270 -1
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts +106 -1
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/streamed_preview_channel.js +269 -17
- package/compiled/src/core/progress_log.d.ts +75 -2
- package/compiled/src/core/progress_log.d.ts.map +1 -1
- package/compiled/src/core/progress_log.js +59 -2
- package/compiled/src/core/progress_log.test.js +75 -1
- package/compiled/src/ifc/dangling_placement_error.d.ts +35 -0
- package/compiled/src/ifc/dangling_placement_error.d.ts.map +1 -0
- package/compiled/src/ifc/dangling_placement_error.js +38 -0
- package/compiled/src/ifc/geometry_dispatch.d.ts +74 -3
- package/compiled/src/ifc/geometry_dispatch.d.ts.map +1 -1
- package/compiled/src/ifc/geometry_dispatch.js +261 -5
- package/compiled/src/ifc/geometry_dispatch.test.js +147 -1
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts +54 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_geometry_extraction.js +153 -20
- package/compiled/src/index.d.ts +1 -1
- package/compiled/src/index.d.ts.map +1 -1
- package/compiled/src/index.js +1 -1
- package/compiled/src/step/dangling_reference_error.d.ts +34 -0
- package/compiled/src/step/dangling_reference_error.d.ts.map +1 -0
- package/compiled/src/step/dangling_reference_error.js +36 -0
- package/compiled/src/step/step_entity_base.d.ts +17 -0
- package/compiled/src/step/step_entity_base.d.ts.map +1 -1
- package/compiled/src/step/step_entity_base.js +28 -4
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -59,6 +59,17 @@ export interface PreviewMeshPayload {
|
|
|
59
59
|
*/
|
|
60
60
|
solid?: boolean;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* One unit a generation attempted and could not extract.
|
|
64
|
+
*
|
|
65
|
+
* `onPlacement` marks the subset waiting on a placement chain the prefix
|
|
66
|
+
* does not hold yet — the only cause worth a retry, because for any other
|
|
67
|
+
* cause a longer index does not change the answer.
|
|
68
|
+
*/
|
|
69
|
+
export interface PreviewDeferral {
|
|
70
|
+
ordinal: number;
|
|
71
|
+
onPlacement: boolean;
|
|
72
|
+
}
|
|
62
73
|
/**
|
|
63
74
|
* A throwaway prefix extraction built by a {@link PreviewSchemaAdapter} —
|
|
64
75
|
* one preview "generation" over a snapshot of the growing columnar index.
|
|
@@ -82,6 +93,19 @@ export interface PreviewPrefixGeneration {
|
|
|
82
93
|
* @return {number} Units actually executed.
|
|
83
94
|
*/
|
|
84
95
|
runUnits(from: number, count: number): number;
|
|
96
|
+
/**
|
|
97
|
+
* Drain the units {@link runUnits} has swallowed an exception for since
|
|
98
|
+
* the last call — the channel's only view of them, because runUnits
|
|
99
|
+
* reports a count and the causes stay inside the adapter.
|
|
100
|
+
*
|
|
101
|
+
* Cleared by the read, so a caller that drains per unit attributes each
|
|
102
|
+
* deferral to the ordinal it just ran. Left unset by adapters that cannot
|
|
103
|
+
* classify their failures; the channel then queues no retries for that
|
|
104
|
+
* schema and behaves exactly as it did before conway#542.
|
|
105
|
+
*
|
|
106
|
+
* @return {PreviewDeferral[]} Deferrals since the last drain.
|
|
107
|
+
*/
|
|
108
|
+
takeDeferrals?(): PreviewDeferral[];
|
|
85
109
|
/**
|
|
86
110
|
* ExpressID identifying a walked geometry (payload identity / dedup).
|
|
87
111
|
*
|
|
@@ -204,7 +228,41 @@ export declare class StreamedPreviewChannel {
|
|
|
204
228
|
private stopped_;
|
|
205
229
|
private timer_?;
|
|
206
230
|
private emittedUnits_;
|
|
231
|
+
/**
|
|
232
|
+
* Preview meshes handed to `onMesh`. Tracked apart from
|
|
233
|
+
* {@link emittedUnits_} because the two genuinely diverge: a unit can
|
|
234
|
+
* place several meshes, and a unit with no representation extracts
|
|
235
|
+
* cleanly while placing none. Reporting only units let the load log say
|
|
236
|
+
* "no mesh, 20 emitted" about one load (codex round 2 on #543).
|
|
237
|
+
*/
|
|
238
|
+
private meshesEmitted_;
|
|
207
239
|
private emittedBytes_;
|
|
240
|
+
private deferredUnits_;
|
|
241
|
+
private deferredOnPlacement_;
|
|
242
|
+
/**
|
|
243
|
+
* Ordinals that deferred on a placement under the CURRENT generation,
|
|
244
|
+
* promoted to {@link retryQueue_} when the next one is built. Held
|
|
245
|
+
* separately so a retry always runs against a longer index than the
|
|
246
|
+
* attempt that failed — re-running one inside its own generation would
|
|
247
|
+
* fail identically and spin.
|
|
248
|
+
*/
|
|
249
|
+
private deferredForRetry_;
|
|
250
|
+
private retryQueue_;
|
|
251
|
+
private retryCursor_;
|
|
252
|
+
private retriedUnits_;
|
|
253
|
+
/**
|
|
254
|
+
* Retry mode (adapter.retryEmptyUnits): units this generation ran that
|
|
255
|
+
* captured nothing. That schema's adapters cannot classify a failure —
|
|
256
|
+
* an assembly unit simply produces no instances until the solids it
|
|
257
|
+
* references are indexed — so an empty unit is its evidence that a
|
|
258
|
+
* longer index is the missing ingredient, standing in for
|
|
259
|
+
* {@link deferredForRetry_} in the preemption gate.
|
|
260
|
+
*/
|
|
261
|
+
private emptyUnitsThisGeneration_;
|
|
262
|
+
/** Ms from channel construction to the first payload handed to `onMesh`
|
|
263
|
+
* — time-to-first-pixel, the number conway#542 exists to move. */
|
|
264
|
+
private firstMeshMs_?;
|
|
265
|
+
private readonly startedMs_;
|
|
208
266
|
/** Ordinal cursor into the unit list (see the adapter's stability
|
|
209
267
|
* notes). */
|
|
210
268
|
private unitOrdinal_;
|
|
@@ -241,6 +299,7 @@ export declare class StreamedPreviewChannel {
|
|
|
241
299
|
private lastInlineTick_;
|
|
242
300
|
private tickIntervalMs_;
|
|
243
301
|
private tickBudgetMs_;
|
|
302
|
+
private tickMaxAttempts_;
|
|
244
303
|
/** Begin ticking (call just before awaiting the parse). */
|
|
245
304
|
start(): void;
|
|
246
305
|
/**
|
|
@@ -261,12 +320,48 @@ export declare class StreamedPreviewChannel {
|
|
|
261
320
|
stop(): void;
|
|
262
321
|
/** True when a cap was hit and the channel retired itself early. */
|
|
263
322
|
get capped(): boolean;
|
|
323
|
+
/**
|
|
324
|
+
* What the preview delivered, and how fast.
|
|
325
|
+
*
|
|
326
|
+
* `firstMeshMs` is time-to-first-pixel measured from channel construction
|
|
327
|
+
* (immediately before the parse starts), undefined when nothing was ever
|
|
328
|
+
* emitted. `meshes` counts what actually reached the consumer, `emitted`
|
|
329
|
+
* counts the units extraction accepted — a unit can place several meshes
|
|
330
|
+
* and a unit with no representation places none, so the line reports
|
|
331
|
+
* both. `deferred` counts units a tick attempted and could not
|
|
332
|
+
* extract, `deferredOnPlacement` the subset waiting on a placement chain
|
|
333
|
+
* the prefix does not hold, and `retried` the attempts that were second
|
|
334
|
+
* looks at an earlier deferral — a retry path that has silently stopped
|
|
335
|
+
* firing shows up here rather than merely as a slower load.
|
|
336
|
+
*
|
|
337
|
+
* The same shape as {@link StorePreviewChannel.previewYield}, so both
|
|
338
|
+
* paths render through one formatter (core/progress_log).
|
|
339
|
+
*
|
|
340
|
+
* @return {object} `{firstMeshMs, meshes, emitted, deferred,
|
|
341
|
+
* deferredOnPlacement, retried}`
|
|
342
|
+
*/
|
|
343
|
+
get previewYield(): {
|
|
344
|
+
firstMeshMs?: number;
|
|
345
|
+
meshes: number;
|
|
346
|
+
emitted: number;
|
|
347
|
+
deferred: number;
|
|
348
|
+
deferredOnPlacement: number;
|
|
349
|
+
retried: number;
|
|
350
|
+
};
|
|
264
351
|
private schedule_;
|
|
265
352
|
/**
|
|
266
353
|
* One pump tick: ensure a generation with pending units exists, then
|
|
267
354
|
* extract + capture under the time budget.
|
|
268
355
|
*/
|
|
269
356
|
private tick_;
|
|
357
|
+
/**
|
|
358
|
+
* Take the deferrals the generation accumulated for the unit just run and
|
|
359
|
+
* fold them into the counters, queueing the placement ones for a second
|
|
360
|
+
* look at the next generation.
|
|
361
|
+
*
|
|
362
|
+
* @param generation The generation that ran the unit.
|
|
363
|
+
*/
|
|
364
|
+
private drainDeferrals_;
|
|
270
365
|
/**
|
|
271
366
|
* Ensure a generation with pending units: keep the current one while
|
|
272
367
|
* it has work; otherwise snapshot a fresh prefix model once the index
|
|
@@ -275,10 +370,20 @@ export declare class StreamedPreviewChannel {
|
|
|
275
370
|
* @return {boolean} True when a generation with pending units exists.
|
|
276
371
|
*/
|
|
277
372
|
private ensureGeneration_;
|
|
373
|
+
/**
|
|
374
|
+
* Whether the current generation has produced evidence that a longer
|
|
375
|
+
* index would help it — the preemption gate. Classic mode: units queued
|
|
376
|
+
* for a retry. Retry mode: units that ran and captured nothing, since
|
|
377
|
+
* that schema's adapter cannot classify a failure.
|
|
378
|
+
*
|
|
379
|
+
* @return {boolean} True when this generation is deferring.
|
|
380
|
+
*/
|
|
381
|
+
private hasDeferred_;
|
|
278
382
|
/**
|
|
279
383
|
* Does the given generation still have units this channel would run —
|
|
280
384
|
* retry mode: not-yet-captured ordinals ahead of the scan; classic
|
|
281
|
-
* mode: ordinals beyond the global forward-only
|
|
385
|
+
* mode: queued retries, or ordinals beyond the global forward-only
|
|
386
|
+
* cursor.
|
|
282
387
|
*
|
|
283
388
|
* @param generation The generation to check.
|
|
284
389
|
* @return {boolean} True when a tick can make progress on it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamed_preview_channel.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/streamed_preview_channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAU5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAA;
|
|
1
|
+
{"version":3,"file":"streamed_preview_channel.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/streamed_preview_channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,9 @@ import { AP214GeometryExtraction, } from "../../AP214E3_2010/ap214_geometry_extr
|
|
|
7
7
|
import { cursorIterator } from "../../indexing/cursor_utilities.js";
|
|
8
8
|
import * as glmatrix from "gl-matrix";
|
|
9
9
|
import { composeTransformF64, deriveCoordinationF64, NORMALIZE_MAT_F64, } from "./coordination_f64.js";
|
|
10
|
+
import { DanglingPlacementError } from "../../ifc/dangling_placement_error.js";
|
|
11
|
+
import { formatPreviewLine } from "../../core/progress_log.js";
|
|
12
|
+
import Logger from "../../logging/logger.js";
|
|
10
13
|
/* eslint-disable no-magic-numbers */
|
|
11
14
|
/** Initial ms between preview pump ticks (interleaves with the parse's
|
|
12
15
|
* yields). The interval decays (TICK_INTERVAL_GROWTH per tick, capped at
|
|
@@ -25,6 +28,26 @@ const FIRST_GENERATION_MIN_RECORDS = 1024;
|
|
|
25
28
|
/** A new generation only when the index grew this much past the previous
|
|
26
29
|
* snapshot (bounds snapshot copies to O(GROWTH/(GROWTH-1)) of the file). */
|
|
27
30
|
const GENERATION_GROWTH_FACTOR = 2;
|
|
31
|
+
/**
|
|
32
|
+
* Deferred units carried into the next generation for a second look.
|
|
33
|
+
*
|
|
34
|
+
* Twin of {@link StorePreviewChannel}'s queue, for the same defect: the
|
|
35
|
+
* channel was strictly forward-only, so a unit whose placement chain lay
|
|
36
|
+
* beyond the prefix was attempted once — at the earliest and therefore most
|
|
37
|
+
* index-starved generation it appeared in — and never again, because
|
|
38
|
+
* `unitOrdinal_` only ever advances and a rebuilt generation regenerates the
|
|
39
|
+
* unit list in the same dense parse order. On a file whose placement chains
|
|
40
|
+
* resolve late that throws nearly everything away: DOWA has 19,854 of its
|
|
41
|
+
* 45,860 products emittable once 70% of the file is indexed, and the store
|
|
42
|
+
* path emitted 1 before this queue existed (conway#542).
|
|
43
|
+
*
|
|
44
|
+
* A retry is affordable in a way a first attempt is not: a deferring attempt
|
|
45
|
+
* fails on an index lookup before any geometry is paged (~0.17 ms measured
|
|
46
|
+
* on the store path, against ~700 ms for a generation rebuild). The cap is
|
|
47
|
+
* here so the queue cannot grow with the model — it only has to keep
|
|
48
|
+
* DEFAULT_MAX_PREVIEW_UNITS worth of candidates in play.
|
|
49
|
+
*/
|
|
50
|
+
const RETRY_QUEUE_MAX = 4096;
|
|
28
51
|
/** Default cap on units the preview channel ever extracts. Preview
|
|
29
52
|
* generations are throwaway extractions whose native geometry is not
|
|
30
53
|
* reclaimed until page teardown (the shim never frees classic scenes
|
|
@@ -78,6 +101,13 @@ export function ifcPreviewAdapter() {
|
|
|
78
101
|
// Preview-only preparation: skip the relationship sweeps whose
|
|
79
102
|
// entity materialization dominates per-generation cost.
|
|
80
103
|
extraction.prepareDemandExtraction(true);
|
|
104
|
+
// Deferrals since the channel last drained them. Product ORDINALS,
|
|
105
|
+
// not localIDs: the channel replays them against a later generation,
|
|
106
|
+
// and `products` is enumerated off the type index in dense parse
|
|
107
|
+
// order, which a longer prefix only extends (see
|
|
108
|
+
// ColumnarIndexSink.snapshot) — so an ordinal means the same product
|
|
109
|
+
// in every generation that holds it.
|
|
110
|
+
let deferrals = [];
|
|
81
111
|
return {
|
|
82
112
|
scene: extraction.scene,
|
|
83
113
|
unitCount: products.length,
|
|
@@ -93,13 +123,25 @@ export function ifcPreviewAdapter() {
|
|
|
93
123
|
++executed;
|
|
94
124
|
}
|
|
95
125
|
}
|
|
96
|
-
catch {
|
|
126
|
+
catch (error) {
|
|
97
127
|
// Unparsed forward reference — the durable pump extracts
|
|
98
|
-
// this product from the full model later.
|
|
128
|
+
// this product from the full model later. Recorded by cause:
|
|
129
|
+
// a dangling placement is a product the index will be able
|
|
130
|
+
// to place once it is longer, and is the one case worth
|
|
131
|
+
// attempting again (conway#542).
|
|
132
|
+
deferrals.push({
|
|
133
|
+
ordinal: where,
|
|
134
|
+
onPlacement: error instanceof DanglingPlacementError,
|
|
135
|
+
});
|
|
99
136
|
}
|
|
100
137
|
}
|
|
101
138
|
return executed;
|
|
102
139
|
},
|
|
140
|
+
takeDeferrals: () => {
|
|
141
|
+
const drained = deferrals;
|
|
142
|
+
deferrals = [];
|
|
143
|
+
return drained;
|
|
144
|
+
},
|
|
103
145
|
geometryExpressID: (geometryLocalID) => model.getElementByLocalID(geometryLocalID)?.expressID,
|
|
104
146
|
recenter: true,
|
|
105
147
|
dispose: () => {
|
|
@@ -226,7 +268,42 @@ export class StreamedPreviewChannel {
|
|
|
226
268
|
this.firstGenerationMinRecords = firstGenerationMinRecords;
|
|
227
269
|
this.stopped_ = false;
|
|
228
270
|
this.emittedUnits_ = 0;
|
|
271
|
+
/**
|
|
272
|
+
* Preview meshes handed to `onMesh`. Tracked apart from
|
|
273
|
+
* {@link emittedUnits_} because the two genuinely diverge: a unit can
|
|
274
|
+
* place several meshes, and a unit with no representation extracts
|
|
275
|
+
* cleanly while placing none. Reporting only units let the load log say
|
|
276
|
+
* "no mesh, 20 emitted" about one load (codex round 2 on #543).
|
|
277
|
+
*/
|
|
278
|
+
this.meshesEmitted_ = 0;
|
|
229
279
|
this.emittedBytes_ = 0;
|
|
280
|
+
/* Units a tick attempted and could not extract, and how many of those were
|
|
281
|
+
* specifically waiting on a placement chain the prefix does not hold yet.
|
|
282
|
+
* Reported on the way out so a blank first load is attributable rather
|
|
283
|
+
* than merely observed (conway#542). */
|
|
284
|
+
this.deferredUnits_ = 0;
|
|
285
|
+
this.deferredOnPlacement_ = 0;
|
|
286
|
+
/**
|
|
287
|
+
* Ordinals that deferred on a placement under the CURRENT generation,
|
|
288
|
+
* promoted to {@link retryQueue_} when the next one is built. Held
|
|
289
|
+
* separately so a retry always runs against a longer index than the
|
|
290
|
+
* attempt that failed — re-running one inside its own generation would
|
|
291
|
+
* fail identically and spin.
|
|
292
|
+
*/
|
|
293
|
+
this.deferredForRetry_ = [];
|
|
294
|
+
this.retryQueue_ = [];
|
|
295
|
+
this.retryCursor_ = 0;
|
|
296
|
+
this.retriedUnits_ = 0;
|
|
297
|
+
/**
|
|
298
|
+
* Retry mode (adapter.retryEmptyUnits): units this generation ran that
|
|
299
|
+
* captured nothing. That schema's adapters cannot classify a failure —
|
|
300
|
+
* an assembly unit simply produces no instances until the solids it
|
|
301
|
+
* references are indexed — so an empty unit is its evidence that a
|
|
302
|
+
* longer index is the missing ingredient, standing in for
|
|
303
|
+
* {@link deferredForRetry_} in the preemption gate.
|
|
304
|
+
*/
|
|
305
|
+
this.emptyUnitsThisGeneration_ = 0;
|
|
306
|
+
this.startedMs_ = Date.now();
|
|
230
307
|
/** Ordinal cursor into the unit list (see the adapter's stability
|
|
231
308
|
* notes). */
|
|
232
309
|
this.unitOrdinal_ = 0;
|
|
@@ -252,6 +329,14 @@ export class StreamedPreviewChannel {
|
|
|
252
329
|
// a loaded runner: the retryEmptyUnits test expected [0,1,2] and got [0,1]
|
|
253
330
|
// in CI while passing locally. Production behaviour is unchanged.
|
|
254
331
|
this.tickBudgetMs_ = TICK_BUDGET_MS;
|
|
332
|
+
// Companion seam to tickBudgetMs_, and unbounded in production: a resident
|
|
333
|
+
// unit attempt pages nothing (the store channel's TICK_MAX_ATTEMPTS exists
|
|
334
|
+
// because its attempts page source through a windowed provider), so the
|
|
335
|
+
// wall clock is the only bound worth paying for here. A test pins it so
|
|
336
|
+
// "this tick left units unattempted" — which is what separates a
|
|
337
|
+
// preemptive rebuild from an exhaustion one — is a fact rather than a race
|
|
338
|
+
// against the budget.
|
|
339
|
+
this.tickMaxAttempts_ = Number.MAX_SAFE_INTEGER;
|
|
255
340
|
}
|
|
256
341
|
/** Begin ticking (call just before awaiting the parse). */
|
|
257
342
|
start() {
|
|
@@ -306,12 +391,57 @@ export class StreamedPreviewChannel {
|
|
|
306
391
|
// Never let a free break the open.
|
|
307
392
|
}
|
|
308
393
|
this.generation_ = void 0;
|
|
394
|
+
// Say what the preview delivered on the way out. The channel is a local
|
|
395
|
+
// of the open call — nothing outside holds it — so a counter not
|
|
396
|
+
// reported here is a counter nobody can read. Same formatter as the
|
|
397
|
+
// store path, and the same one Share renders (core/progress_log), so a
|
|
398
|
+
// pasted browser log and a pasted CLI run read identically.
|
|
399
|
+
//
|
|
400
|
+
// Unconditional, not gated on emittedUnits_ or deferredUnits_ being
|
|
401
|
+
// nonzero: a channel that never reached firstGenerationMinRecords, or
|
|
402
|
+
// whose every generation build threw, is precisely the worst-case
|
|
403
|
+
// blank-first-load this issue exists to make diagnosable, and
|
|
404
|
+
// formatPreviewLine already renders that case as "no mesh, 0 emitted,
|
|
405
|
+
// 0 deferred". Suppressing the line there made an enabled preview that
|
|
406
|
+
// produced nothing indistinguishable from a preview that never ran
|
|
407
|
+
// (codex round 1 on #543).
|
|
408
|
+
Logger.info(formatPreviewLine(this.previewYield));
|
|
309
409
|
}
|
|
310
410
|
/** True when a cap was hit and the channel retired itself early. */
|
|
311
411
|
get capped() {
|
|
312
412
|
return this.emittedUnits_ >= this.maxUnits ||
|
|
313
413
|
this.emittedBytes_ >= this.maxBytes;
|
|
314
414
|
}
|
|
415
|
+
/**
|
|
416
|
+
* What the preview delivered, and how fast.
|
|
417
|
+
*
|
|
418
|
+
* `firstMeshMs` is time-to-first-pixel measured from channel construction
|
|
419
|
+
* (immediately before the parse starts), undefined when nothing was ever
|
|
420
|
+
* emitted. `meshes` counts what actually reached the consumer, `emitted`
|
|
421
|
+
* counts the units extraction accepted — a unit can place several meshes
|
|
422
|
+
* and a unit with no representation places none, so the line reports
|
|
423
|
+
* both. `deferred` counts units a tick attempted and could not
|
|
424
|
+
* extract, `deferredOnPlacement` the subset waiting on a placement chain
|
|
425
|
+
* the prefix does not hold, and `retried` the attempts that were second
|
|
426
|
+
* looks at an earlier deferral — a retry path that has silently stopped
|
|
427
|
+
* firing shows up here rather than merely as a slower load.
|
|
428
|
+
*
|
|
429
|
+
* The same shape as {@link StorePreviewChannel.previewYield}, so both
|
|
430
|
+
* paths render through one formatter (core/progress_log).
|
|
431
|
+
*
|
|
432
|
+
* @return {object} `{firstMeshMs, meshes, emitted, deferred,
|
|
433
|
+
* deferredOnPlacement, retried}`
|
|
434
|
+
*/
|
|
435
|
+
get previewYield() {
|
|
436
|
+
return {
|
|
437
|
+
firstMeshMs: this.firstMeshMs_,
|
|
438
|
+
meshes: this.meshesEmitted_,
|
|
439
|
+
emitted: this.emittedUnits_,
|
|
440
|
+
deferred: this.deferredUnits_,
|
|
441
|
+
deferredOnPlacement: this.deferredOnPlacement_,
|
|
442
|
+
retried: this.retriedUnits_,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
315
445
|
// eslint-disable-next-line require-jsdoc
|
|
316
446
|
schedule_() {
|
|
317
447
|
if (this.stopped_ || this.capped) {
|
|
@@ -341,6 +471,7 @@ export class StreamedPreviewChannel {
|
|
|
341
471
|
}
|
|
342
472
|
const active = this.generation_;
|
|
343
473
|
const { generation } = active;
|
|
474
|
+
let attempts = 0;
|
|
344
475
|
if (this.adapter.retryEmptyUnits === true) {
|
|
345
476
|
// Retry mode: scan the fixed unit list, skipping units that
|
|
346
477
|
// already captured instances on an earlier (or this) generation.
|
|
@@ -348,32 +479,70 @@ export class StreamedPreviewChannel {
|
|
|
348
479
|
// counts here are small by construction (assembly roots).
|
|
349
480
|
while (this.retryScan_ < generation.unitCount &&
|
|
350
481
|
this.emittedUnits_ < this.maxUnits &&
|
|
482
|
+
attempts < this.tickMaxAttempts_ &&
|
|
351
483
|
Date.now() < deadline) {
|
|
352
484
|
const ordinal = this.retryScan_++;
|
|
353
485
|
if (this.completedUnits_.has(ordinal)) {
|
|
354
486
|
continue;
|
|
355
487
|
}
|
|
488
|
+
++attempts;
|
|
356
489
|
const executed = generation.runUnits(ordinal, 1);
|
|
357
490
|
if (executed > 0 && this.captureNewInstances_() > 0) {
|
|
358
491
|
this.completedUnits_.add(ordinal);
|
|
359
492
|
++this.emittedUnits_;
|
|
360
493
|
}
|
|
494
|
+
else {
|
|
495
|
+
++this.emptyUnitsThisGeneration_;
|
|
496
|
+
}
|
|
361
497
|
}
|
|
362
498
|
return;
|
|
363
499
|
}
|
|
364
500
|
let extractedThisTick = 0;
|
|
365
|
-
while (this.
|
|
501
|
+
while (this.hasPendingUnits_(generation) &&
|
|
366
502
|
this.emittedUnits_ + extractedThisTick < this.maxUnits &&
|
|
503
|
+
attempts < this.tickMaxAttempts_ &&
|
|
367
504
|
Date.now() < deadline) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
505
|
+
++attempts;
|
|
506
|
+
// Retries first: they are the units the index has most recently
|
|
507
|
+
// become able to place, and they are cheaper than a fresh attempt
|
|
508
|
+
// whichever way they go.
|
|
509
|
+
const isRetry = this.retryCursor_ < this.retryQueue_.length;
|
|
510
|
+
const ordinal = isRetry ?
|
|
511
|
+
this.retryQueue_[this.retryCursor_++] : this.unitOrdinal_++;
|
|
512
|
+
if (isRetry) {
|
|
513
|
+
++this.retriedUnits_;
|
|
514
|
+
}
|
|
515
|
+
extractedThisTick += generation.runUnits(ordinal, 1);
|
|
516
|
+
this.drainDeferrals_(generation);
|
|
371
517
|
}
|
|
372
518
|
if (extractedThisTick > 0) {
|
|
373
519
|
this.captureNewInstances_();
|
|
374
520
|
this.emittedUnits_ += extractedThisTick;
|
|
375
521
|
}
|
|
376
522
|
}
|
|
523
|
+
/**
|
|
524
|
+
* Take the deferrals the generation accumulated for the unit just run and
|
|
525
|
+
* fold them into the counters, queueing the placement ones for a second
|
|
526
|
+
* look at the next generation.
|
|
527
|
+
*
|
|
528
|
+
* @param generation The generation that ran the unit.
|
|
529
|
+
*/
|
|
530
|
+
drainDeferrals_(generation) {
|
|
531
|
+
const deferrals = generation.takeDeferrals?.();
|
|
532
|
+
if (deferrals === void 0) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
for (const deferral of deferrals) {
|
|
536
|
+
++this.deferredUnits_;
|
|
537
|
+
if (!deferral.onPlacement) {
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
++this.deferredOnPlacement_;
|
|
541
|
+
if (this.deferredForRetry_.length < RETRY_QUEUE_MAX) {
|
|
542
|
+
this.deferredForRetry_.push(deferral.ordinal);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
377
546
|
/**
|
|
378
547
|
* Ensure a generation with pending units: keep the current one while
|
|
379
548
|
* it has work; otherwise snapshot a fresh prefix model once the index
|
|
@@ -383,10 +552,41 @@ export class StreamedPreviewChannel {
|
|
|
383
552
|
*/
|
|
384
553
|
ensureGeneration_() {
|
|
385
554
|
const active = this.generation_;
|
|
386
|
-
|
|
555
|
+
const records = this.sink.topLevelCount;
|
|
556
|
+
// Rebuild on INDEX GROWTH, not on running out of units. The order of
|
|
557
|
+
// these two tests is the whole behaviour of the channel on a large file.
|
|
558
|
+
//
|
|
559
|
+
// It used to keep the current generation for as long as that generation
|
|
560
|
+
// still had an unattempted unit, and only then consider rebuilding. A
|
|
561
|
+
// generation snapshotted at FIRST_GENERATION_MIN_RECORDS already lists
|
|
562
|
+
// thousands of products, and a tick attempts a handful of them per
|
|
563
|
+
// cadence interval, so on anything large the list never emptied and the
|
|
564
|
+
// rebuild never fired — the store path's twin of this gate left DOWA
|
|
565
|
+
// extracting against a snapshot of its first 1024 records for all 9 s of
|
|
566
|
+
// its parse, which is why 100% of its attempts deferred and its first
|
|
567
|
+
// mesh landed at 98.3% of the file (conway#542).
|
|
568
|
+
//
|
|
569
|
+
// Preempting makes generations arrive on the index's schedule —
|
|
570
|
+
// O(log records) of them, GENERATION_GROWTH_FACTOR apart — and the units
|
|
571
|
+
// the old generation had not reached carry over untouched, because
|
|
572
|
+
// `unitOrdinal_` indexes a dense parse-order list that a longer snapshot
|
|
573
|
+
// only extends.
|
|
574
|
+
// Eligibility to rebuild at all — the original growth gate, unchanged.
|
|
575
|
+
const growthReady = records >= this.lastSnapshotRecords_ * GENERATION_GROWTH_FACTOR &&
|
|
576
|
+
records >= this.lastFailedSnapshotRecords_ * GENERATION_GROWTH_FACTOR;
|
|
577
|
+
// Whether to rebuild EARLY, without waiting for the current generation's
|
|
578
|
+
// units to run out. Only worth it for a generation that is actually
|
|
579
|
+
// deferring: a longer index cannot help one whose units extract fine,
|
|
580
|
+
// and preempting anyway costs the case that already works best — on PSB,
|
|
581
|
+
// which defers nothing, unconditional preemption pushed the store path's
|
|
582
|
+
// first mesh from 269 ms out to 495 ms. Units waiting for a retry (or,
|
|
583
|
+
// in retry mode, units that captured nothing) are precisely the evidence
|
|
584
|
+
// that more index is the missing ingredient.
|
|
585
|
+
const preempt = active !== void 0 && growthReady && this.hasDeferred_();
|
|
586
|
+
if (!preempt && active !== void 0 &&
|
|
587
|
+
this.hasPendingUnits_(active.generation)) {
|
|
387
588
|
return true;
|
|
388
589
|
}
|
|
389
|
-
const records = this.sink.topLevelCount;
|
|
390
590
|
if (records < this.firstGenerationMinRecords) {
|
|
391
591
|
return false;
|
|
392
592
|
}
|
|
@@ -419,10 +619,14 @@ export class StreamedPreviewChannel {
|
|
|
419
619
|
// Prefix grew but cannot build yet — wait for more records.
|
|
420
620
|
return false;
|
|
421
621
|
}
|
|
622
|
+
// A generation that adds no new units is still worth building when
|
|
623
|
+
// deferred ones are waiting: what changed is the INDEX behind them,
|
|
624
|
+
// which is the only reason a retry could now succeed.
|
|
422
625
|
const newGenerationPending = this.adapter.retryEmptyUnits === true ?
|
|
423
626
|
generation.unitCount > 0 &&
|
|
424
627
|
this.completedUnits_.size < generation.unitCount :
|
|
425
|
-
generation.unitCount > this.unitOrdinal_
|
|
628
|
+
generation.unitCount > this.unitOrdinal_ ||
|
|
629
|
+
this.deferredForRetry_.length > 0;
|
|
426
630
|
if (!newGenerationPending) {
|
|
427
631
|
// Nothing this prefix can add — free it and wait for more records.
|
|
428
632
|
// (The active generation, if any, keeps its scan state untouched.)
|
|
@@ -436,9 +640,26 @@ export class StreamedPreviewChannel {
|
|
|
436
640
|
}
|
|
437
641
|
// Retry mode: a fresh generation re-runs every not-yet-captured unit.
|
|
438
642
|
this.retryScan_ = 0;
|
|
439
|
-
|
|
440
|
-
//
|
|
441
|
-
//
|
|
643
|
+
this.emptyUnitsThisGeneration_ = 0;
|
|
644
|
+
// Deferrals of the outgoing generation become this one's retry queue —
|
|
645
|
+
// the whole point of building it early. Carry the OLD queue's
|
|
646
|
+
// unconsumed suffix forward too, not just this generation's fresh
|
|
647
|
+
// deferrals: preemption can fire mid-drain of retryQueue_ (a tick's
|
|
648
|
+
// attempt budget against an index that grew enough to trigger a
|
|
649
|
+
// rebuild before the queue emptied), and every un-popped entry is a
|
|
650
|
+
// unit whose ordinal unitOrdinal_ has already passed — replacing the
|
|
651
|
+
// queue outright, rather than concatenating, would strand them exactly
|
|
652
|
+
// the way abandoned deferrals were stranded before this fix existed
|
|
653
|
+
// (conway#542, codex round 1 on #543).
|
|
654
|
+
this.retryQueue_ = [
|
|
655
|
+
...this.retryQueue_.slice(this.retryCursor_),
|
|
656
|
+
...this.deferredForRetry_,
|
|
657
|
+
].slice(0, RETRY_QUEUE_MAX);
|
|
658
|
+
this.retryCursor_ = 0;
|
|
659
|
+
this.deferredForRetry_ = [];
|
|
660
|
+
// The outgoing generation's instances are all captured (capture runs
|
|
661
|
+
// per tick, after the units it ran) — free its native scenes before
|
|
662
|
+
// adopting the new one.
|
|
442
663
|
try {
|
|
443
664
|
active?.generation.dispose();
|
|
444
665
|
}
|
|
@@ -451,10 +672,25 @@ export class StreamedPreviewChannel {
|
|
|
451
672
|
};
|
|
452
673
|
return true;
|
|
453
674
|
}
|
|
675
|
+
/**
|
|
676
|
+
* Whether the current generation has produced evidence that a longer
|
|
677
|
+
* index would help it — the preemption gate. Classic mode: units queued
|
|
678
|
+
* for a retry. Retry mode: units that ran and captured nothing, since
|
|
679
|
+
* that schema's adapter cannot classify a failure.
|
|
680
|
+
*
|
|
681
|
+
* @return {boolean} True when this generation is deferring.
|
|
682
|
+
*/
|
|
683
|
+
hasDeferred_() {
|
|
684
|
+
if (this.adapter.retryEmptyUnits === true) {
|
|
685
|
+
return this.emptyUnitsThisGeneration_ > 0;
|
|
686
|
+
}
|
|
687
|
+
return this.deferredForRetry_.length > 0;
|
|
688
|
+
}
|
|
454
689
|
/**
|
|
455
690
|
* Does the given generation still have units this channel would run —
|
|
456
691
|
* retry mode: not-yet-captured ordinals ahead of the scan; classic
|
|
457
|
-
* mode: ordinals beyond the global forward-only
|
|
692
|
+
* mode: queued retries, or ordinals beyond the global forward-only
|
|
693
|
+
* cursor.
|
|
458
694
|
*
|
|
459
695
|
* @param generation The generation to check.
|
|
460
696
|
* @return {boolean} True when a tick can make progress on it.
|
|
@@ -464,7 +700,8 @@ export class StreamedPreviewChannel {
|
|
|
464
700
|
return this.retryScan_ < generation.unitCount &&
|
|
465
701
|
this.completedUnits_.size < generation.unitCount;
|
|
466
702
|
}
|
|
467
|
-
return this.
|
|
703
|
+
return this.retryCursor_ < this.retryQueue_.length ||
|
|
704
|
+
this.unitOrdinal_ < generation.unitCount;
|
|
468
705
|
}
|
|
469
706
|
/**
|
|
470
707
|
* Walk the current generation's scene and emit every not-yet-captured
|
|
@@ -547,7 +784,9 @@ export class StreamedPreviewChannel {
|
|
|
547
784
|
this.emittedBytes_ +=
|
|
548
785
|
(vertexData.length + indexData.length) * BYTES_PER_FLOAT;
|
|
549
786
|
}
|
|
787
|
+
this.firstMeshMs_ ??= Date.now() - this.startedMs_;
|
|
550
788
|
this.onMesh(payload);
|
|
789
|
+
++this.meshesEmitted_;
|
|
551
790
|
++emitted;
|
|
552
791
|
if (this.emittedBytes_ >= this.maxBytes) {
|
|
553
792
|
return emitted;
|
|
@@ -566,11 +805,24 @@ export class StreamedPreviewChannel {
|
|
|
566
805
|
return;
|
|
567
806
|
}
|
|
568
807
|
const active = this.generation_;
|
|
569
|
-
|
|
808
|
+
// The classic-mode pending test, spelled out rather than shared with
|
|
809
|
+
// hasPendingUnits_: this seam walks the unit list forward whatever
|
|
810
|
+
// the adapter's retry semantics are (ap214_streamed_open.test.ts
|
|
811
|
+
// drains a retryEmptyUnits adapter through it), and retry mode's
|
|
812
|
+
// `retryScan_` is advanced by ticks only, so borrowing that test here
|
|
813
|
+
// would never terminate.
|
|
814
|
+
if (this.retryCursor_ >= this.retryQueue_.length &&
|
|
815
|
+
this.unitOrdinal_ >= active.generation.unitCount) {
|
|
570
816
|
return;
|
|
571
817
|
}
|
|
572
|
-
const
|
|
573
|
-
|
|
818
|
+
const isRetry = this.retryCursor_ < this.retryQueue_.length;
|
|
819
|
+
const ordinal = isRetry ?
|
|
820
|
+
this.retryQueue_[this.retryCursor_++] : this.unitOrdinal_++;
|
|
821
|
+
if (isRetry) {
|
|
822
|
+
++this.retriedUnits_;
|
|
823
|
+
}
|
|
824
|
+
const executed = active.generation.runUnits(ordinal, 1);
|
|
825
|
+
this.drainDeferrals_(active.generation);
|
|
574
826
|
if (executed > 0) {
|
|
575
827
|
this.captureNewInstances_();
|
|
576
828
|
++this.emittedUnits_;
|