Insert complete diff files while streaming Rapid Diffs

What does this MR do and why?

Rapid Diffs streams diff HTML into the page by parsing it node by node as bytes arrive. Every added node fires its own mutation record, so each file turns into many small render tasks, and browser extensions that inspect every added node (like password managers) can freeze the page for seconds. This MR parses the stream in a hidden, same-origin frame and moves each fully parsed file into the live page in one operation, using an existing marker that already signals when a file is done. There are no observers, timers, or text scanning involved, so nothing can collide with diff content and there is no heuristic for detecting the last file. Files now appear once complete instead of row by row, which is not noticeable at normal streaming speed, and there is no other UI change.

Measurements

Local 1,000-file merge request (998 streamed files, about 85k elements), Overview tab then Changes tab, headless 1440x900, no extensions, master (with the file browser MR already merged) and this branch served by the same local stack, warm-up run before recording, 4 runs each, medians, all runs from one afternoon. Blocked is total main-thread time in frames longer than 50 ms during streaming; longest is the longest single task. Time to the last file is not reported because the local server produces the stream in a burst whose timing varies by about half a second between runs.

Variant Chromium blocked Chromium longest task Firefox blocked Firefox longest task
master 424 ms 121 ms 2,240 ms 657 ms
this MR 368 ms 134 ms 588 ms 216 ms

Firefox blocked time drops to about a quarter and the longest task to a third. Chromium blocked time drops by about 13 percent; its longest task is within noise of master.

Why not re-parse complete files in the page instead

An earlier version of this MR scanned the streamed text for the closing tag of each file and re-parsed each complete file in the page. It measured Chromium 360 ms / 96 ms and Firefox 1,014 ms / 319 ms, so it was equal in Chromium and much slower in Firefox. Firefox profiles show why: nodes produced by fragment parsing cost about eight times more frame construction on insertion than nodes moved from another document (549 ms versus 70 ms), plus more paint work; parsing itself is negligible in both browsers. It also relied on finding a tag name in HTML text, which cannot collide with escaped diff content today but is a textual contract rather than a parser guarantee. That version is kept as a tag for reference.

Other alternatives measured

Moving each file element itself when its marker is parsed cost Chromium 2,834 ms, because Blink is very slow adopting a subtree whose root was touched from script. This is why the range-based move never touches file nodes. Without the frame base URL, the frame issued about 10,000 memory-cache lookups for icon references during the stream, worth roughly 100 ms of Chromium blocked time (462 ms before, 368 ms after).

Password manager extensions

With 1Password in Firefox, a 301-file MR previously blocked about 9.3 s with single freezes of 5 s. With complete-file insertion measured earlier, that dropped to 1.4 s.

Verified in the browser

Chromium 151 and Firefox 152: 998 of 998 streamed files mounted, every marker directly after its file and none inside, the frame removed when the stream ends, no node left owned by another document, the diffs list height identical to the sum of file heights, and icons in streamed files render exactly like icons in server-rendered files. Replacing a collapsed file with "Show changes" still mounts the new file and focuses it. Not verified: Safari, since remote automation is disabled on the test machine; the existing Safari streaming workaround was adjusted for the new marker position and stays in place.

Reproduction steps

  1. Open an MR with several hundred files, go to Overview then Changes, and record a Performance profile during streaming.
  2. Optional: attach a MutationObserver with childList and subtree on the diffs container; it reports one record per network chunk instead of one per node.
  3. Open a large MR with images in the diff and confirm images still lazy-load after streaming finishes.
  4. Confirm the file header icons render correctly on streamed files.
  5. On a collapsed large file, click "Show changes" and confirm it expands and is interactive.
  6. Optional: with 1Password in Firefox, confirm the multi-second freeze is gone.

References

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Stanislav Lashmanov

Merge request reports

Loading
Loading