Commit d5a7ee5
committed
fix(parsers): make the sub-composition scan linear, not quadratic
The shared scan ran one regex with two open-ended `[^>]*` spans across the whole
file. On input full of `<` with no `>`, every `<` starts a scan to end-of-string
that then backtracks. Measured on the previous implementation:
10k chars of '<' -> 41ms
20k chars of '<' -> 165ms
40k chars of '<' -> 660ms
80k chars of '<' -> 2640ms
Four times the work for twice the input. Its caller allows files up to 20MB, and
a 20MB run of '<' did not finish in over ten minutes.
The regex itself predates this branch (it was inline in lint), but this branch is
what made it matter: the scan is now a shared exported function wired
synchronously into `createRenderPlan`, so it runs on every `hyperframes render`
before the render starts. A truncated download or a blob of stray `<` could hang
the plan step before any video is produced. That is a render-blocking failure,
which is exactly what this feature was built never to risk.
The scan now walks tag by tag with `indexOf` and applies a bounded attribute
regex to one already-delimited tag, so no quantifier ranges over the whole file.
Same inputs, after:
80k chars of '<' -> 0ms
20MB of '<' -> 27ms
20MB of real mounts -> 91ms
Semantics are unchanged: the previous regex also treated `>` as a tag terminator
and also required a closing `>`, so an unterminated final tag was never a match
before either. Fixing it at the shared owner fixes lint's path too.
The regression test needs no timing assertion to bite. A megabyte of `<` ran for
minutes under the old scan, so the case simply failed on the suite timeout.1 parent 412808a commit d5a7ee5
2 files changed
Lines changed: 71 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
3 | 7 | | |
4 | 8 | | |
5 | 9 | | |
| |||
55 | 59 | | |
56 | 60 | | |
57 | 61 | | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
45 | 48 | | |
46 | 49 | | |
47 | 50 | | |
| |||
63 | 66 | | |
64 | 67 | | |
65 | 68 | | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
66 | 78 | | |
67 | 79 | | |
68 | | - | |
69 | 80 | | |
70 | 81 | | |
71 | 82 | | |
72 | | - | |
73 | | - | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
74 | 96 | | |
75 | 97 | | |
76 | 98 | | |
| |||
0 commit comments