Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] find_smallest_cycle: enhance search prioritization
Date: Thu, 19 Nov 2020 08:31:46
Message-Id: 20201119082844.1770118-1-zmedico@gentoo.org
1 Enhance the find_smallest_cycle function to prioritize its
2 search so that it will minimize the use of installed packages
3 to break cycles. When installed packages must be used to
4 break cycles, it will now prefer to do this for runtime
5 dependencies over buildtime dependencies, since it's
6 preferable to build against latest versions of buildtime
7 dependencies whenever possible. This should solve some cases
8 of bug 199856 which have been triggered by unsafe reliance
9 on installed packages to break cycles.
10
11 Bug: https://bugs.gentoo.org/754903
12 Signed-off-by: Zac Medico <zmedico@g.o>
13 ---
14 lib/_emerge/DepPriorityNormalRange.py | 2 +
15 lib/_emerge/DepPrioritySatisfiedRange.py | 52 +++++++++++++-----------
16 lib/_emerge/depgraph.py | 41 +++++++++++--------
17 3 files changed, 54 insertions(+), 41 deletions(-)
18
19 diff --git a/lib/_emerge/DepPriorityNormalRange.py b/lib/_emerge/DepPriorityNormalRange.py
20 index 5f3f3da70..10f205a3b 100644
21 --- a/lib/_emerge/DepPriorityNormalRange.py
22 +++ b/lib/_emerge/DepPriorityNormalRange.py
23 @@ -14,6 +14,7 @@ class DepPriorityNormalRange:
24 """
25 MEDIUM = 3
26 MEDIUM_SOFT = 2
27 + MEDIUM_POST = 2
28 SOFT = 1
29 NONE = 0
30
31 @@ -37,6 +38,7 @@ class DepPriorityNormalRange:
32
33 ignore_medium = _ignore_runtime
34 ignore_medium_soft = _ignore_runtime_post
35 + ignore_medium_post = _ignore_runtime_post
36 ignore_soft = _ignore_optional
37
38 DepPriorityNormalRange.ignore_priority = (
39 diff --git a/lib/_emerge/DepPrioritySatisfiedRange.py b/lib/_emerge/DepPrioritySatisfiedRange.py
40 index e056e676f..df2439f1f 100644
41 --- a/lib/_emerge/DepPrioritySatisfiedRange.py
42 +++ b/lib/_emerge/DepPrioritySatisfiedRange.py
43 @@ -8,17 +8,18 @@ class DepPrioritySatisfiedRange:
44
45 not satisfied and buildtime HARD
46 not satisfied and runtime 7 MEDIUM
47 - not satisfied and runtime_post 6 MEDIUM_SOFT
48 - satisfied and buildtime_slot_op 5 SOFT
49 - satisfied and buildtime 4 SOFT
50 - satisfied and runtime 3 SOFT
51 - satisfied and runtime_post 2 SOFT
52 + satisfied and buildtime_slot_op 6 MEDIUM_SOFT
53 + satisfied and buildtime 5 MEDIUM_SOFT
54 + satisfied and runtime 4 MEDIUM_SOFT
55 + runtime_post 3 MEDIUM_POST
56 + satisfied and runtime_post 2 MEDIUM_POST
57 optional 1 SOFT
58 (none of the above) 0 NONE
59 """
60 MEDIUM = 7
61 MEDIUM_SOFT = 6
62 - SOFT = 5
63 + MEDIUM_POST = 3
64 + SOFT = 1
65 NONE = 0
66
67 @classmethod
68 @@ -37,15 +38,23 @@ class DepPrioritySatisfiedRange:
69 return False
70 return bool(priority.runtime_post)
71
72 + @classmethod
73 + def _ignore_runtime_post(cls, priority):
74 + if priority.__class__ is not DepPriority:
75 + return False
76 + return bool(priority.optional or priority.runtime_post)
77 +
78 @classmethod
79 def _ignore_satisfied_runtime(cls, priority):
80 if priority.__class__ is not DepPriority:
81 return False
82 if priority.optional:
83 return True
84 - if not priority.satisfied:
85 + if priority.buildtime:
86 return False
87 - return not priority.buildtime
88 + if not priority.runtime:
89 + return True
90 + return bool(priority.satisfied)
91
92 @classmethod
93 def _ignore_satisfied_buildtime(cls, priority):
94 @@ -61,37 +70,32 @@ class DepPrioritySatisfiedRange:
95 def _ignore_satisfied_buildtime_slot_op(cls, priority):
96 if priority.__class__ is not DepPriority:
97 return False
98 - return bool(priority.optional or \
99 - priority.satisfied)
100 -
101 - @classmethod
102 - def _ignore_runtime_post(cls, priority):
103 - if priority.__class__ is not DepPriority:
104 - return False
105 - return bool(priority.optional or \
106 - priority.satisfied or \
107 - priority.runtime_post)
108 + if priority.optional:
109 + return True
110 + if priority.satisfied:
111 + return True
112 + return not priority.buildtime and not priority.runtime
113
114 @classmethod
115 def _ignore_runtime(cls, priority):
116 if priority.__class__ is not DepPriority:
117 return False
118 - return bool(priority.satisfied or \
119 - priority.optional or \
120 - not priority.buildtime)
121 + return bool(priority.optional or
122 + priority.satisfied or priority.runtime)
123
124 ignore_medium = _ignore_runtime
125 - ignore_medium_soft = _ignore_runtime_post
126 - ignore_soft = _ignore_satisfied_buildtime
127 + ignore_medium_soft = _ignore_satisfied_buildtime_slot_op
128 + ignore_medium_post = _ignore_runtime_post
129 + ignore_soft = _ignore_optional
130
131
132 DepPrioritySatisfiedRange.ignore_priority = (
133 None,
134 DepPrioritySatisfiedRange._ignore_optional,
135 DepPrioritySatisfiedRange._ignore_satisfied_runtime_post,
136 + DepPrioritySatisfiedRange._ignore_runtime_post,
137 DepPrioritySatisfiedRange._ignore_satisfied_runtime,
138 DepPrioritySatisfiedRange._ignore_satisfied_buildtime,
139 DepPrioritySatisfiedRange._ignore_satisfied_buildtime_slot_op,
140 - DepPrioritySatisfiedRange._ignore_runtime_post,
141 DepPrioritySatisfiedRange._ignore_runtime
142 )
143 diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
144 index 6aaacfe44..b18d5d717 100644
145 --- a/lib/_emerge/depgraph.py
146 +++ b/lib/_emerge/depgraph.py
147 @@ -7905,7 +7905,7 @@ class depgraph:
148 if check_asap_parent:
149 for node in nodes:
150 parents = mygraph.parent_nodes(node,
151 - ignore_priority=DepPrioritySatisfiedRange.ignore_soft)
152 + ignore_priority=DepPrioritySatisfiedRange.ignore_medium_soft)
153 if any(x in asap_nodes for x in parents):
154 selected_nodes = [node]
155 break
156 @@ -7921,7 +7921,7 @@ class depgraph:
157
158 if not selected_nodes:
159
160 - def find_smallest_cycle(mergeable_nodes, priority_ranges):
161 + def find_smallest_cycle(mergeable_nodes, local_priority_range):
162 if prefer_asap and asap_nodes:
163 nodes = asap_nodes
164 else:
165 @@ -7938,18 +7938,25 @@ class depgraph:
166 # these smaller independent cycles.
167 smallest_cycle = None
168 ignore_priority = None
169 - for node in nodes:
170 - if not mygraph.parent_nodes(node):
171 - continue
172 - for local_priority_range in priority_ranges:
173 +
174 + for priority in (local_priority_range.ignore_priority[i] for i in range(
175 + local_priority_range.MEDIUM_POST,
176 + local_priority_range.MEDIUM_SOFT + 1)):
177 + for node in nodes:
178 + if not mygraph.parent_nodes(node):
179 + continue
180 selected_nodes = set()
181 - if gather_deps(local_priority_range.ignore_medium_soft,
182 + if gather_deps(priority,
183 mergeable_nodes, selected_nodes, node):
184 if smallest_cycle is None or \
185 len(selected_nodes) < len(smallest_cycle):
186 smallest_cycle = selected_nodes
187 - ignore_priority = local_priority_range.ignore_medium_soft
188 - break
189 + ignore_priority = priority
190 +
191 + # Exit this loop with the lowest possible priority, which
192 + # minimizes the use of installed packages to break cycles.
193 + if smallest_cycle is not None:
194 + break
195
196 return smallest_cycle, ignore_priority
197
198 @@ -7963,7 +7970,7 @@ class depgraph:
199 for local_priority_range in priority_ranges:
200 mergeable_nodes = set(get_nodes(ignore_priority=local_priority_range.ignore_medium))
201 if mergeable_nodes:
202 - selected_nodes, ignore_priority = find_smallest_cycle(mergeable_nodes, priority_ranges)
203 + selected_nodes, ignore_priority = find_smallest_cycle(mergeable_nodes, local_priority_range)
204 if selected_nodes:
205 break
206
207 @@ -8001,19 +8008,19 @@ class depgraph:
208 (selected_nodes[0],), noiselevel=-1)
209
210 if selected_nodes and ignore_priority is not None:
211 - # Try to merge ignored medium_soft deps as soon as possible
212 + # Try to merge ignored medium_post deps as soon as possible
213 # if they're not satisfied by installed packages.
214 for node in selected_nodes:
215 children = set(mygraph.child_nodes(node))
216 soft = children.difference(
217 - mygraph.child_nodes(node,
218 - ignore_priority=DepPrioritySatisfiedRange.ignore_soft))
219 - medium_soft = children.difference(
220 mygraph.child_nodes(node,
221 ignore_priority = \
222 - DepPrioritySatisfiedRange.ignore_medium_soft))
223 - medium_soft -= soft
224 - for child in medium_soft:
225 + DepPrioritySatisfiedRange.ignore_soft))
226 + medium_post = children.difference(
227 + mygraph.child_nodes(node,
228 + ignore_priority=DepPrioritySatisfiedRange.ignore_medium_post))
229 + medium_post -= soft
230 + for child in medium_post:
231 if child in selected_nodes:
232 continue
233 if child in asap_nodes:
234 --
235 2.26.2

Replies