Profile convert to metadata format is O(n²) per tag in `mergeProfiles` (13.8.3+), blocks the event loop for minutes on large profiles

未关闭
#3,681 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

@sfdcmatt 已经在做这个了。

开始于 2026年11月5日。

  • #1867 来自 @sfdcmatt —— 未关闭

评估

难度
4/5
预计耗时
3-5 天
新手友好度
35/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
停滞
技术栈
node.js, typescript
领域
performance

调研方向

Start with src/convert/convertContext/profileMetadataFinalizer.ts and inspect mergeProfiles, especially the duplicate check described around line 235. Compare conversion time and per-entry zip hashes using the reported 73-profile reproduction; the linked pull request #1867 indicates work is already underway. Done means large-profile conversion avoids the quadratic slowdown while preserving the reported output behavior.

由索引模型根据 Issue 内容生成。

描述

bug

Versions: @salesforce/source-deploy-retrieve 13.10.1 (same mergeProfiles loop since 13.8.3, when ProfileMetadataFinalizer was added; 13.8.2 and earlier copied profile files as-is). Node 26.0.0, macOS.

Repro: a project with 73 profiles in one package directory (103 MB of *.profile-meta.xml, large fieldPermissions / objectPermissions lists). ComponentSet.fromSource(profilesDir) then new MetadataConverter().convert(cs, 'metadata', { type: 'zip' }):

Version convert longest event-loop block zip bytes
13.7.0 2.1 s ~0.1 s 7,116,094
13.10.1 247 s one continuous block 7,116,094
13.10.1 + fix below 7.9-8.3 s 5.9-6.3 s 7,116,094

Output is byte-identical in all three (per-entry sha256 of the zip match).

Root cause: src/convert/convertContext/profileMetadataFinalizer.ts, mergeProfiles, line 235:

if (mergedValues.some((existing) => isDeepStrictEqual(existing, entry))) continue;

Every entry is compared with every entry already merged for that tag, synchronously, so a tag with n entries costs n²/2 isDeepStrictEqual calls. This runs even when a profile has only one source file, where there is nothing to merge.

Proposed fix: (1) when profiles.length === 1, return the single profile's entries as-is (root attributes built the same way); (2) for several pieces, dedupe with a Set keyed by a deterministic serialization of each entry (sorted object keys) instead of the linear scan. The singleton-conflict check is unchanged.

Behavior note: with (1), exact duplicate entries inside one profile file are kept, as in 13.8.2 and earlier; 13.8.3-13.10.1 drop them. Duplicates across pieces are still removed.

The remaining ~6 s block after the fix is fast-xml-parser parsing all profiles back to back in parseXml (~4 s) plus JsToXml (~1.3 s), from the finalizer parsing and re-serializing profiles that 13.8.2 streamed unchanged. Not addressed here.

主要语言
没有语言数据
星标
575
派生
80
平均合并
11 小时 37 分钟
30 天内合并 PR
6

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

forcedotcom/cli 的其他 Issue

查看 forcedotcom/cli 的全部 Issue

相似的 Issue

更多 Performance Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。