Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙️ Pengaturan Proxy Target

Skip to content

perf(scope): check for flattened edges without parsing them in the importer - #10881

Open
luvkapur wants to merge 1 commit into
masterfrom
perf/import-has-flattened-edges
Open

luvkapur wants to merge 1 commit into
masterfrom
perf/import-has-flattened-edges

Conversation

@luvkapur

@luvkapur luvkapur commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

The flattened edges of every imported version were parsed only to test whether they exist.

Current behavior

  1. When a component is imported with its dependency graph (preferDependencyGraph, the default of bit import and bit lane import), the importer does not fetch its flattened dependencies: multipleCompsDefsToVersionDeps, bitIdsToVersionDeps and the missing-dependencies check in importMany only need to know whether the version has flattened edges.
  2. To know that, they call Version.getFlattenedEdges(), which loads the edges Source of the version, parses its JSON and builds a ComponentID for each end of each edge. A version of a component with hundreds of dependencies has thousands of edges (7,604 for teambit.component/snapping). The result is then used only for .length.
  3. Nothing else in these flows reads the parsed edges: no code outside Version reads _flattenedEdges synchronously, and the VersionDependencies objects read the flattened dependencies, not the edges.

Fix

Version.hasFlattenedEdges(repo) answers the question without parsing: it loads the Source and checks whether its content is an empty JSON array by reading its first bytes, with the same fallbacks as getFlattenedEdges() (the edges saved in the Version object itself when the Source is missing, the already loaded edges when present). The three importer sites use it. getFlattenedEdges() is unchanged for the callers that need the edges (the snap graph, the dependents import).

Tests

Whole-command time, same machine, dev binary of the worktree, no profiler. Each round runs every build once, in a rotated order, with the builds swapped in place (no recompilation between runs); five rounds. For the bit.cloud import, the time that bit.cloud takes to start each response is subtracted: it is 0.4 s or 11 s at random for every build (the request is the same), and it hides the client time.

Flow (fresh workspace each run) master this change gain #10880 + #10884 #10880 + #10884 + this change gain
bit lane import of a 273-component lane of a private scope from bit.cloud (5,480 objects), client time 34.5 s [31.5–39.8] 30.9 s [28.6–32.3] 10% 15.6 s [14.8–16.1] 13.0 s [12.7–13.5] (4 runs: one failed with an ENOENT error of the bit.cloud scope) 17%
bit lane import of a 178-component lane from a local bare scope (3,469 objects), no network 14.4 s [14.1–14.9] 11.8 s [11.6–12.0] 18% 10.6 s [10.5–10.7] 7.9 s [7.7–8.3] 25%

The change removes the same work in every run: the phase from the last object written to importMany, completed! in the debug log goes from 4.1–4.5 s to 1.4–1.8 s on the bit.cloud import. On master, the slow writes of the fetched objects (#10880, #10884) dominate the import, so the ranges of the first comparison overlap on bit.cloud; with them in place, the ranges do not overlap in either flow. The object stores written by the builds are identical: the same files with the same bytes.

The spec in version.spec.ts checks hasFlattenedEdges() against getFlattenedEdges() for a Source with edges, an empty Source with whitespace, a missing Source with and without edges saved in the Version, and after the edges were loaded. It passes on master as well for the shared cases: the change keeps the behavior and changes only the time.

…porter

When a component is imported with its dependency graph, the importer only
needs to know whether a version has flattened edges. It called
getFlattenedEdges(), which parses the edges JSON and builds a ComponentID for
each end of each edge, to read the length of the result.

Version.hasFlattenedEdges() now answers from the first bytes of the Source,
with the same fallbacks as getFlattenedEdges(), and the three importer sites
use it.

The parsing was 2.8 s of the 16 s of CPU of a 272-component lane import; the
import went from 32.6 s to 28.6 s, and from a local bare scope from 13.8 s to
11.0 s.
@luvkapur
luvkapur force-pushed the perf/import-has-flattened-edges branch from 4d71709 to 073f186 Compare October 28, 2026 04:23
@luvkapur
luvkapur marked this pull request as ready for review October 28, 2026 14:27
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Avoid parsing flattened edges during dependency-graph imports

✨ Enhancement 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Check edge presence without parsing every imported version’s flattened-edge graph.
• Preserve legacy and already-loaded edge fallbacks while leaving full edge parsing available to
 other callers.
• Add behavior tests; measured lane imports improved by 10% remotely and 18% locally.
Diagram

graph TD
  I["Scope importer"] --> H["Version edge check"] --> S["Edge Source"] --> C{"Edges present?"} -->|yes| G["Skip dependency fetch"]
  C -->|no| F["Fetch flattened deps"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Persist an edge-presence flag on Version
  • ➕ Could avoid loading the edge Source for presence checks.
  • ➖ Requires a serialization change and compatibility handling for existing versions.
  • ➖ Adds another value that must remain consistent with stored edges.

Recommendation: Keep the Source-content check: it removes the expensive parsing and ComponentID construction without changing stored objects or callers that need full edges. A persisted flag is worth considering only if Source loading becomes a demonstrated bottleneck.

Files changed (3) +72 / -13

Enhancement (2) +30 / -12
scope-components-importer.tsUse edge-presence checks in three import paths +5/-12

Use edge-presence checks in three import paths

• Replaces full flattened-edge loading with hasFlattenedEdges() in dependency-fetch selection and missing-dependency traversal. Flattened dependencies remain loaded for downstream synchronous consumers.

components/legacy/scope/component-ops/scope-components-importer.ts

version.tsAdd a parsing-free flattened-edge presence API +25/-0

Add a parsing-free flattened-edge presence API

• Adds hasFlattenedEdges(), which checks loaded edges first, inspects the beginning of referenced Source content, and falls back to edges stored on the Version. getFlattenedEdges() remains unchanged for callers needing parsed edges.

scopes/scope/objects/models/version.ts

Tests (1) +42 / -1
version.spec.tsCover edge-presence compatibility cases +42/-1

Cover edge-presence compatibility cases

• Tests populated and empty Sources, whitespace around an empty array, missing-Source legacy fallbacks, and edges previously loaded through getFlattenedEdges().

scopes/scope/objects/models/version.spec.ts

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Corrupt edge data passes import unnoticed 🐞 Bug ☼ Reliability
Description
isEmptyJsonArray() classifies a referenced edge source as non-empty after inspecting only its
opening bytes, without validating the complete JSON. If that source contains malformed data such as
[, importer paths using preferDependencyGraph skip flattened-dependency checks that previously
failed while getFlattenedEdges() parsed the source.
Code

scopes/scope/objects/models/version.ts[65]

+  return contents[i] === 0x5d; // "]"
Evidence
The new helper returns false for [ because the byte after [ is not ], so hasFlattenedEdges()
returns true. The existing getter instead parses the full contents and throws; the importer now uses
the boolean to return before checking flattened dependencies.

scopes/scope/objects/models/version.ts[58-65]
scopes/scope/objects/models/version.ts[286-307]
scopes/scope/objects/models/version.ts[314-320]
components/legacy/scope/component-ops/scope-components-importer.ts[1104-1107]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A referenced edge source containing malformed JSON can be treated as having edges, allowing the importer to skip dependency checks instead of failing as it did previously.

## Fix Focus Areas
- scopes/scope/objects/models/version.ts[58-65]
- scopes/scope/objects/models/version.ts[314-320]
- components/legacy/scope/component-ops/scope-components-importer.ts[1104-1107]

## Recommended Fix
Ensure referenced edge sources are validated before their presence check can justify skipping dependencies. Preserve the fast path for sources already known to be valid, and test a malformed referenced source against the previous failure behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: Auto: ⚖️ Balanced: Runtime importer behavior and fallback semantics warrant a careful single-pass review.

Grey Divider

Tip of the day
💡 Did you know, you can turn on the rule miner and Qodo learns your standards from review history

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant