-
-
Notifications
You must be signed in to change notification settings - Fork 14.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pythonCatchConflictsHook: prevent exponential worst-case #305619
pythonCatchConflictsHook: prevent exponential worst-case #305619
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Maybe we should target the python-updates branch here?
Add a test where a conflicting package can be found at the end of multiple dependency chains. This is far too simple an example to demonstrate the ill effects of exponential time complexity, but does serve to demonstrate how the error output changes when each path is only visited once.
The hook performs a depth first search on the graph defined by propagatedBuildInputs. This traverses all paths through the graph, except for any cycles. In the worst case with a highly connected graph, this search can take exponential time. In practice, this means that in cases with long dependency chains and multiple packages depending on the same package, the hook can take several hours to run. Avoid this problem by keeping track of already visited paths and only visiting each path once. This makes the search complete in linear time. The visible effect of this change is that, if a conflict is found, only one dependency chain that leads to the conflicting package is printed, rather than all the possible dependency chains.
Now that we only visit each path once, a few things can be simplified. We no longer have to keep a list of different dependency chains leading to a package, since only one chain will ever be found. Also, the already visited check also takes care of cycles, so the other cycle check can be removed.
…itespace Currently, nix-support/propagated-build-inputs is parsed by splitting on a single space. This means that if this file contains multiple spaces separating two paths, the build_inputs list will end up containing an empty string. Instead, call split() with no arguments, which splits on runs of whitespace and also ignores whitespace at the beginning and end of the string, eliminating the need for strip().
8d18ed3
to
f9de72f
Compare
I updated the target branch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks for the fix. It looks good to be merged.
I think it would be better if it would display the first 5 paths leading to a collision instead of just one. I guess this would still be in linear time and it would allow to better grasp the complexity of the underlying dependency conflict and make it easier to debug it.
But I don't want to block this. This could be done in a separate PR
Description of changes
The hook performs a depth first search on the graph defined by
propagatedBuildInputs
. This traverses all paths through the graph, except for any cycles. In the worst case with a highly connected graph, this search can take exponential time. In practice, this means that in cases with long dependency chains and multiple packages depending on the same package, the hook can take several hours to run.Avoid this problem by keeping track of already visited paths and only visiting each path once. This makes the search complete in linear time.
The visible effect of this change is that, if a conflict is found, only one dependency chain that leads to the conflicting package is printed, rather than all the possible dependency chains.
Now that only one dependency chain will be found for each package, a few other simplifications are possible and are included in a separate commit.
Also, add a test to demonstrate the change in output with multiple dependency chains, and fix a minor bug in parsing
nix-support/propagated-build-inputs
.The tests pass and I have tested building a few Python packages.
Fixes #305599
cc @DavHau @phaer
Things done
nix.conf
? (See Nix manual)sandbox = relaxed
sandbox = true
nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)Add a 👍 reaction to pull requests you find important.