Commit c0dfd54
Fix quadratic key disambiguation in lock files
LockFile::toJSON() assigns each node a unique key, disambiguating
collisions by appending _2, _3, and so on. The search restarted at 2 on
every collision, so the k-th node sharing a base name cost k iterations
and the whole pass was O(n^2) in the number of colliding nodes.
This is easy to hit in practice. Every flake that depends on many other
flakes accumulates one "systems", "flake-compat" or "nixpkgs" node per
dependency, and they all share a base name. Because the serialized lock
file is passed to call-flake.nix on every evaluation, the cost is paid
by `nix eval`, `nix flake metadata` and `nix flake lock` alike, not just
when writing the file back out.
Track the highest suffix already handed out per base key and resume from
there. The insert check is retained, so a name that legitimately appears
in the lock file (e.g. an input actually called "systems_2") is still
skipped over and the resulting keys are unchanged.
Measured on a flake with n inputs that each pull in their own "systems",
timing `nix eval` of an output that touches no input:
inputs nodes before after speedup
500 1000 0.64s 0.15s 4.3x
1000 2000 0.88s 0.16s 5.5x
2000 4000 3.05s 0.28s 10.9x
4000 8000 11.49s 0.54s 21.3x
Lock files produced before and after are byte-identical, verified on the
cases above, on a lock file containing pre-existing "systems_2",
"systems_3" and "systems_5" inputs, and on an existing real-world flake.
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>1 parent df1878b commit c0dfd54
1 file changed
Lines changed: 9 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
187 | 188 | | |
188 | 189 | | |
189 | 190 | | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
190 | 196 | | |
191 | 197 | | |
192 | 198 | | |
193 | 199 | | |
194 | 200 | | |
195 | 201 | | |
196 | | - | |
197 | | - | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
198 | 205 | | |
199 | 206 | | |
200 | 207 | | |
| |||
0 commit comments