docs(runtime): explain import scheduling and dependency selection
This commit is contained in:
@@ -5,10 +5,15 @@
|
||||
import type { ImportLocator } from './imports.ts';
|
||||
import { fault } from '../canvas-core/values.ts';
|
||||
|
||||
/** Ready SCCs are indivisible. Ordinary records retain source-order FIFO selection. */
|
||||
/** pending按源顺序输入;返回有序原子组,不实际提交,缺依赖的组继续等待而非直接丢失。 */
|
||||
/** Ready SCCs are indivisible; source order guides each readiness scan. */
|
||||
/** pending 由调用方按源顺序提供且 key 唯一;先找 SCC,再按组内/组间最早源索引扫描。
|
||||
* 缺外部依赖的组会跳过,可选择其后的已就绪组;同轮后面补齐依赖也不回头重扫,留给下一次调用。
|
||||
* 不修改 committed/pending,不读取源或实际提交;输出数组可变且 row 沿用输入引用。
|
||||
* limits 与 locator 成本须先校验;本函数不核对真实编码字节/changes,也没有中途取消或异步让出。 */
|
||||
export function selectImportGroups(pending: readonly ImportLocator[], committed: ReadonlySet<string>, limits: {units: number; bytes: number; changes: number}): readonly (readonly ImportLocator[])[] {
|
||||
// 正向边仅含当前pending内依赖,反向表用于第二次DFS;原index保留稳定源顺序。
|
||||
// byKey 用 key→原记录/源索引,edges 是依赖邻接表,reverse 是依赖→引用者表。
|
||||
// 建图只含 pending 内边;外部 key 暂不入图,稍后用 committed 判定是否满足。
|
||||
// 全段建图与排序同步完成,runner 应先限制 pending 大小,不能靠返回组数限制本次计算成本。
|
||||
const byKey = new Map(pending.map((row, index) => [row.key, {row, index}])), edges = new Map<string, string[]>(), reverse = new Map<string, string[]>();
|
||||
for (const row of pending) {
|
||||
const dependencies = row.dependencies.filter(key => byKey.has(key)); edges.set(row.key, dependencies);
|
||||
@@ -39,11 +44,13 @@ export function selectImportGroups(pending: readonly ImportLocator[], committed:
|
||||
for (const group of components) {
|
||||
const internal = new Set(group.map(row => row.key));
|
||||
if (!group.every(row => row.dependencies.every(key => available.has(key) || internal.has(key)))) continue;
|
||||
// SCC不可拆:单组字节/changes超安全上限必须报错,不能分批提交半个循环引用。
|
||||
// 只有依赖就绪的组才检查硬成本;超限直接抛错,即使前面已选了组也不会返回部分结果。
|
||||
// SCC 不可拆,依赖未就绪的超限组仍先等待,不能用拆组绕过循环引用完整性。
|
||||
const size = group.reduce((sum, row) => sum + row.byteLength, 0), count = group.reduce((sum, row) => sum + row.changeCount, 0);
|
||||
if (size > limits.bytes || count > limits.changes) throw fault('import_dependency_group_capacity');
|
||||
// The frame's adaptive unit budget is soft for one SCC, byte/change safety limits are hard.
|
||||
// 第一组可超过units软预算以闭合环;后续组和字节/changes总预算仍保守限制。
|
||||
// 第一组可超过 units 软预算以闭合环,字节/changes 总量始终不得超限。
|
||||
// 后续组放不下就继续找后面的较小可用组,不以 break 阻止其它独立组;available 只加入实际 chosen 的键。
|
||||
if (units && units + group.length > limits.units || bytes + size > limits.bytes || changes + count > limits.changes) continue;
|
||||
chosen.push(group); units += group.length; bytes += size; changes += count; for (const row of group) available.add(row.key);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user