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 コメント 0 件 リアクション 0 件 担当者 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 の本文から書いたものです。

説明

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分
マージ済み PR(30日)
6

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

forcedotcom/cli のほかの issue

forcedotcom/cli の issue をすべて見る

似ている issue

Performance の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。