Commit 0f6b1feb authored by Samuel Giddins's avatar Samuel Giddins

[Resolver] Speed up #resolver_specs_by_target

This brings the time down from 90s to 4s for us, by reducing the amount of times we perform graph traversal from something like O(x^n^n) to O(log n)
parent a1a2b981
...@@ -133,19 +133,13 @@ module Pod ...@@ -133,19 +133,13 @@ module Pod
# #
def resolver_specs_by_target def resolver_specs_by_target
@resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target| @resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target|
dependencies = {}
@podfile_dependency_cache.target_definition_list.each do |target| @podfile_dependency_cache.target_definition_list.each do |target|
specs = @podfile_dependency_cache.target_definition_dependencies(target).flat_map do |dep| vertices = valid_dependencies_for_target(target)
name = dep.name
node = @activated.vertex_named(name)
(valid_dependencies_for_target_from_node(target, dependencies, node) << node).map { |s| [s, node.payload.test_specification?] }
end
resolver_specs_by_target[target] = specs. resolver_specs_by_target[target] = vertices.
group_by(&:first). map do |vertex|
map do |vertex, spec_test_only_tuples|
test_only = spec_test_only_tuples.all? { |tuple| tuple[1] }
payload = vertex.payload payload = vertex.payload
test_only = vertex.recursive_predecessors.all? { |v| !v.root? || v.payload.test_specification? } && (!vertex.root? || payload.test_specification?)
spec_source = payload.respond_to?(:spec_source) && payload.spec_source spec_source = payload.respond_to?(:spec_source) && payload.spec_source
ResolverSpecification.new(payload, test_only, spec_source) ResolverSpecification.new(payload, test_only, spec_source)
end. end.
...@@ -235,31 +229,29 @@ module Pod ...@@ -235,31 +229,29 @@ module Pod
def requirement_satisfied_by?(requirement, activated, spec) def requirement_satisfied_by?(requirement, activated, spec)
version = spec.version version = spec.version
return false unless requirement.requirement.satisfied_by?(version) return false unless requirement.requirement.satisfied_by?(version)
shared_possibility_versions, prerelease_requirement = possibility_versions_for_root_name(requirement, activated) return false unless valid_possibility_version_for_root_name?(requirement, activated, spec)
return false if !shared_possibility_versions.empty? && !shared_possibility_versions.include?(version)
return false if version.prerelease? && !prerelease_requirement
return false unless spec_is_platform_compatible?(activated, requirement, spec) return false unless spec_is_platform_compatible?(activated, requirement, spec)
true true
end end
def possibility_versions_for_root_name(requirement, activated) def valid_possibility_version_for_root_name?(requirement, activated, spec)
prerelease_requirement = requirement.prerelease? || requirement.external_source prerelease_requirement = requirement.prerelease? || requirement.external_source || !spec.version.prerelease?
existing = activated.vertices.values.flat_map do |vertex|
activated.each do |vertex|
next unless vertex.payload next unless vertex.payload
next unless Specification.root_name(vertex.name) == requirement.root_name next unless Specification.root_name(vertex.name) == requirement.root_name
prerelease_requirement ||= vertex.requirements.any? { |r| r.prerelease? || r.external_source } prerelease_requirement ||= vertex.requirements.any? { |r| r.prerelease? || r.external_source }
if vertex.payload.respond_to?(:possibilities) if vertex.payload.respond_to?(:version)
vertex.payload.possibilities.map(&:version) return true if vertex.payload.version == spec.version
else break
vertex.payload.version
end end
end.compact end
[existing, prerelease_requirement] prerelease_requirement
end end
private :possibility_versions_for_root_name private :valid_possibility_version_for_root_name?
# Sort dependencies so that the ones that are easiest to resolve are first. # Sort dependencies so that the ones that are easiest to resolve are first.
# Easiest to resolve is (usually) defined by: # Easiest to resolve is (usually) defined by:
...@@ -543,8 +535,10 @@ module Pod ...@@ -543,8 +535,10 @@ module Pod
# #
# @return [Bool] # @return [Bool]
def spec_is_platform_compatible?(dependency_graph, dependency, spec) def spec_is_platform_compatible?(dependency_graph, dependency, spec)
return true if locked_dependencies.vertex_named(spec.name) # HACK: this probably isn't safe?
vertex = dependency_graph.vertex_named(dependency.name) vertex = dependency_graph.vertex_named(dependency.name)
predecessors = vertex.recursive_predecessors.select(&:root) predecessors = vertex.recursive_predecessors.select(&:root?)
predecessors << vertex if vertex.root? predecessors << vertex if vertex.root?
platforms_to_satisfy = predecessors.flat_map(&:explicit_requirements).flat_map { |r| @platforms_by_dependency[r] }.uniq platforms_to_satisfy = predecessors.flat_map(&:explicit_requirements).flat_map { |r| @platforms_by_dependency[r] }.uniq
...@@ -566,18 +560,21 @@ module Pod ...@@ -566,18 +560,21 @@ module Pod
# An array of target-appropriate nodes whose `payload`s are # An array of target-appropriate nodes whose `payload`s are
# dependencies for `target`. # dependencies for `target`.
# #
def valid_dependencies_for_target_from_node(target, dependencies, node) def valid_dependencies_for_target(target)
dependencies[[node.name, target.platform]] ||= begin dependencies = Set.new
validate_platform(node.payload, target) @podfile_dependency_cache.target_definition_dependencies(target).each do |dep|
dependency_nodes = [] node = @activated.vertex_named(dep.name)
node.outgoing_edges.each do |edge| add_valid_dependencies_from_node(node, target, dependencies)
next unless edge_is_valid_for_target_platform?(edge, target.platform) end
dependency_nodes << edge.destination dependencies
end end
dependency_nodes.flat_map do |item| def add_valid_dependencies_from_node(node, target, dependencies)
valid_dependencies_for_target_from_node(target, dependencies, item) return unless dependencies.add?(node)
end.concat(dependency_nodes).uniq validate_platform(node.payload, target)
node.outgoing_edges.each do |edge|
next unless edge_is_valid_for_target_platform?(edge, target.platform)
add_valid_dependencies_from_node(edge.destination, target, dependencies)
end end
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment