File: | src/order.c |
Warning: | line 664, column 4 Value stored to 'j' is never read |
1 | /* |
2 | * Copyright (c) 2007-2015, SUSE LLC |
3 | * |
4 | * This program is licensed under the BSD license, read LICENSE.BSD |
5 | * for further information |
6 | */ |
7 | |
8 | /* |
9 | * order.c |
10 | * |
11 | * Transaction ordering |
12 | */ |
13 | |
14 | #include <stdio.h> |
15 | #include <stdlib.h> |
16 | #include <unistd.h> |
17 | #include <string.h> |
18 | #include <assert.h> |
19 | |
20 | #include "transaction.h" |
21 | #include "bitmap.h" |
22 | #include "pool.h" |
23 | #include "repo.h" |
24 | #include "util.h" |
25 | |
26 | struct _TransactionElement { |
27 | Id p; /* solvable id */ |
28 | Id edges; /* pointer into edges data */ |
29 | Id mark; |
30 | }; |
31 | |
32 | struct _TransactionOrderdata { |
33 | struct _TransactionElement *tes; |
34 | int ntes; |
35 | Id *invedgedata; |
36 | int ninvedgedata; |
37 | Queue *cycles; |
38 | }; |
39 | |
40 | #define TYPE_BROKEN(1<<0) (1<<0) |
41 | #define TYPE_CON(1<<1) (1<<1) |
42 | |
43 | #define TYPE_REQ_P(1<<2) (1<<2) |
44 | #define TYPE_PREREQ_P(1<<3) (1<<3) |
45 | |
46 | #define TYPE_REQ(1<<4) (1<<4) |
47 | #define TYPE_PREREQ(1<<5) (1<<5) |
48 | |
49 | #define TYPE_CYCLETAIL(1<<16) (1<<16) |
50 | #define TYPE_CYCLEHEAD(1<<17) (1<<17) |
51 | |
52 | #define EDGEDATA_BLOCK127 127 |
53 | |
54 | void |
55 | transaction_clone_orderdata(Transaction *trans, Transaction *srctrans) |
56 | { |
57 | struct _TransactionOrderdata *od = srctrans->orderdata; |
58 | if (!od) |
59 | return; |
60 | trans->orderdata = solv_calloc(1, sizeof(*trans->orderdata)); |
61 | trans->orderdata->tes = solv_memdup2(od->tes, od->ntes, sizeof(*od->tes)); |
62 | trans->orderdata->ntes = od->ntes; |
63 | trans->orderdata->invedgedata = solv_memdup2(od->invedgedata, od->ninvedgedata, sizeof(Id)); |
64 | trans->orderdata->ninvedgedata = od->ninvedgedata; |
65 | if (od->cycles) |
66 | { |
67 | trans->orderdata->cycles = solv_calloc(1, sizeof(Queue)); |
68 | queue_init_clone(trans->orderdata->cycles, od->cycles); |
69 | } |
70 | } |
71 | |
72 | void |
73 | transaction_free_orderdata(Transaction *trans) |
74 | { |
75 | if (trans->orderdata) |
76 | { |
77 | struct _TransactionOrderdata *od = trans->orderdata; |
78 | od->tes = solv_free(od->tes); |
79 | od->invedgedata = solv_free(od->invedgedata); |
80 | if (od->cycles) |
81 | { |
82 | queue_free(od->cycles); |
83 | od->cycles = solv_free(od->cycles); |
84 | } |
85 | trans->orderdata = solv_free(trans->orderdata); |
86 | } |
87 | } |
88 | |
89 | struct orderdata { |
90 | Transaction *trans; |
91 | struct _TransactionElement *tes; |
92 | int ntes; |
93 | Id *edgedata; |
94 | int nedgedata; |
95 | Id *invedgedata; |
96 | |
97 | Queue cycles; |
98 | Queue cyclesdata; |
99 | int ncycles; |
100 | }; |
101 | |
102 | static int |
103 | addteedge(struct orderdata *od, int from, int to, int type) |
104 | { |
105 | int i; |
106 | struct _TransactionElement *te; |
107 | |
108 | if (from == to) |
109 | return 0; |
110 | |
111 | /* printf("edge %d(%s) -> %d(%s) type %x\n", from, pool_solvid2str(pool, od->tes[from].p), to, pool_solvid2str(pool, od->tes[to].p), type); */ |
112 | |
113 | te = od->tes + from; |
114 | for (i = te->edges; od->edgedata[i]; i += 2) |
115 | if (od->edgedata[i] == to) |
116 | break; |
117 | /* test of brokenness */ |
118 | if (type == TYPE_BROKEN(1<<0)) |
119 | return od->edgedata[i] && (od->edgedata[i + 1] & TYPE_BROKEN(1<<0)) != 0 ? 1 : 0; |
120 | if (od->edgedata[i]) |
121 | { |
122 | od->edgedata[i + 1] |= type; |
123 | return 0; |
124 | } |
125 | if (i + 1 == od->nedgedata) |
126 | { |
127 | /* printf("tail add %d\n", i - te->edges); */ |
128 | if (!i) |
129 | te->edges = ++i; |
130 | od->edgedata = solv_extend(od->edgedata, od->nedgedata, 3, sizeof(Id), EDGEDATA_BLOCK127); |
131 | } |
132 | else |
133 | { |
134 | /* printf("extend %d\n", i - te->edges); */ |
135 | od->edgedata = solv_extend(od->edgedata, od->nedgedata, 3 + (i - te->edges), sizeof(Id), EDGEDATA_BLOCK127); |
136 | if (i > te->edges) |
137 | memcpy(od->edgedata + od->nedgedata, od->edgedata + te->edges, sizeof(Id) * (i - te->edges)); |
138 | i = od->nedgedata + (i - te->edges); |
139 | te->edges = od->nedgedata; |
140 | } |
141 | od->edgedata[i] = to; |
142 | od->edgedata[i + 1] = type; |
143 | od->edgedata[i + 2] = 0; /* end marker */ |
144 | od->nedgedata = i + 3; |
145 | return 0; |
146 | } |
147 | |
148 | static int |
149 | addedge(struct orderdata *od, Id from, Id to, int type) |
150 | { |
151 | Transaction *trans = od->trans; |
152 | Pool *pool = trans->pool; |
153 | Solvable *s; |
154 | struct _TransactionElement *te; |
155 | int i; |
156 | |
157 | /* printf("addedge %d %d type %d\n", from, to, type); */ |
158 | s = pool->solvables + from; |
159 | if (s->repo == pool->installed && trans->transaction_installed[from - pool->installed->start]) |
160 | { |
161 | /* obsolete, map to install */ |
162 | if (trans->transaction_installed[from - pool->installed->start] > 0) |
163 | from = trans->transaction_installed[from - pool->installed->start]; |
164 | else |
165 | { |
166 | int ret = 0; |
167 | Queue ti; |
168 | Id tibuf[5]; |
169 | |
170 | queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf)); |
171 | transaction_all_obs_pkgs(trans, from, &ti); |
172 | for (i = 0; i < ti.count; i++) |
173 | ret |= addedge(od, ti.elements[i], to, type); |
174 | queue_free(&ti); |
175 | return ret; |
176 | } |
177 | } |
178 | s = pool->solvables + to; |
179 | if (s->repo == pool->installed && trans->transaction_installed[to - pool->installed->start]) |
180 | { |
181 | /* obsolete, map to install */ |
182 | if (trans->transaction_installed[to - pool->installed->start] > 0) |
183 | to = trans->transaction_installed[to - pool->installed->start]; |
184 | else |
185 | { |
186 | int ret = 0; |
187 | Queue ti; |
188 | Id tibuf[5]; |
189 | |
190 | queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf)); |
191 | transaction_all_obs_pkgs(trans, to, &ti); |
192 | for (i = 0; i < ti.count; i++) |
193 | ret |= addedge(od, from, ti.elements[i], type); |
194 | queue_free(&ti); |
195 | return ret; |
196 | } |
197 | } |
198 | |
199 | /* map from/to to te numbers */ |
200 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
201 | if (te->p == to) |
202 | break; |
203 | if (i == od->ntes) |
204 | return 0; |
205 | to = i; |
206 | |
207 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
208 | if (te->p == from) |
209 | break; |
210 | if (i == od->ntes) |
211 | return 0; |
212 | |
213 | return addteedge(od, i, to, type); |
214 | } |
215 | |
216 | static inline int |
217 | havescripts(Pool *pool, Id solvid) |
218 | { |
219 | Solvable *s = pool->solvables + solvid; |
220 | const char *dep; |
221 | if (s->requires) |
222 | { |
223 | Id req, *reqp; |
224 | int inpre = 0; |
225 | reqp = s->repo->idarraydata + s->requires; |
226 | while ((req = *reqp++) != 0) |
227 | { |
228 | if (req == SOLVABLE_PREREQMARKER) |
229 | { |
230 | inpre = 1; |
231 | continue; |
232 | } |
233 | if (!inpre) |
234 | continue; |
235 | dep = pool_id2str(pool, req); |
236 | if (*dep == '/' && strcmp(dep, "/sbin/ldconfig") != 0) |
237 | return 1; |
238 | } |
239 | } |
240 | return 0; |
241 | } |
242 | |
243 | static void |
244 | addsolvableedges(struct orderdata *od, Solvable *s) |
245 | { |
246 | Transaction *trans = od->trans; |
247 | Pool *pool = trans->pool; |
248 | Id req, *reqp, con, *conp; |
249 | Id p, p2, pp2; |
250 | int i, j, pre, numins; |
251 | Repo *installed = pool->installed; |
252 | Solvable *s2; |
253 | Queue reqq; |
254 | int provbyinst; |
255 | |
256 | #if 0 |
257 | printf("addsolvableedges %s\n", pool_solvable2str(pool, s)); |
258 | #endif |
259 | p = s - pool->solvables; |
260 | queue_init(&reqq); |
261 | if (s->requires) |
262 | { |
263 | reqp = s->repo->idarraydata + s->requires; |
264 | pre = TYPE_REQ(1<<4); |
265 | while ((req = *reqp++) != 0) |
266 | { |
267 | if (req == SOLVABLE_PREREQMARKER) |
268 | { |
269 | pre = TYPE_PREREQ(1<<5); |
270 | continue; |
271 | } |
272 | #if 0 |
273 | if (pre != TYPE_PREREQ(1<<5) && installed && s->repo == installed) |
274 | { |
275 | /* ignore normal requires if we're getting obsoleted */ |
276 | if (trans->transaction_installed[p - pool->installed->start]) |
277 | continue; |
278 | } |
279 | #endif |
280 | queue_empty(&reqq); |
281 | numins = 0; /* number of packages to be installed providing it */ |
282 | provbyinst = 0; /* provided by kept package */ |
283 | FOR_PROVIDES(p2, pp2, req)for (pp2 = pool_whatprovides(pool, req) ; (p2 = pool->whatprovidesdata [pp2++]) != 0; ) |
284 | { |
285 | s2 = pool->solvables + p2; |
286 | if (p2 == p) |
287 | { |
288 | reqq.count = 0; /* self provides */ |
289 | break; |
290 | } |
291 | if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2)((&trans->transactsmap)->map[(p2) >> 3] & (1 << ((p2) & 7)))) |
292 | { |
293 | provbyinst = 1; |
294 | #if 0 |
295 | printf("IGNORE inst provides %s by %s\n", pool_dep2str(pool, req), pool_solvable2str(pool, s2)); |
296 | reqq.count = 0; /* provided by package that stays installed */ |
297 | break; |
298 | #else |
299 | continue; |
300 | #endif |
301 | } |
302 | if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2)((&trans->transactsmap)->map[(p2) >> 3] & (1 << ((p2) & 7)))) |
303 | continue; /* package stays uninstalled */ |
304 | |
305 | if (s->repo == installed) |
306 | { |
307 | /* s gets uninstalled */ |
308 | queue_pushunique(&reqq, p2); |
309 | if (s2->repo != installed) |
310 | numins++; |
311 | } |
312 | else |
313 | { |
314 | if (s2->repo == installed) |
315 | continue; /* s2 gets uninstalled */ |
316 | queue_pushunique(&reqq, p2); |
317 | } |
318 | } |
319 | if (provbyinst) |
320 | { |
321 | /* prune to harmless ->inst edges */ |
322 | for (i = j = 0; i < reqq.count; i++) |
323 | if (pool->solvables[reqq.elements[i]].repo != installed) |
324 | reqq.elements[j++] = reqq.elements[i]; |
325 | reqq.count = j; |
326 | } |
327 | |
328 | if (numins && reqq.count) |
329 | { |
330 | if (s->repo == installed) |
331 | { |
332 | for (i = 0; i < reqq.count; i++) |
333 | { |
334 | if (pool->solvables[reqq.elements[i]].repo == installed) |
335 | { |
336 | for (j = 0; j < reqq.count; j++) |
337 | { |
338 | if (pool->solvables[reqq.elements[j]].repo != installed) |
339 | { |
340 | if (trans->transaction_installed[reqq.elements[i] - pool->installed->start] == reqq.elements[j]) |
341 | continue; /* no self edge */ |
342 | #if 0 |
343 | printf("add interrreq uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, reqq.elements[i]), pool_dep2str(pool, req), pool_solvid2str(pool, reqq.elements[j])); |
344 | #endif |
345 | addedge(od, reqq.elements[i], reqq.elements[j], pre == TYPE_PREREQ(1<<5) ? TYPE_PREREQ_P(1<<3) : TYPE_REQ_P(1<<2)); |
346 | } |
347 | } |
348 | } |
349 | } |
350 | } |
351 | /* no mixed types, remove all deps on uninstalls */ |
352 | for (i = j = 0; i < reqq.count; i++) |
353 | if (pool->solvables[reqq.elements[i]].repo != installed) |
354 | reqq.elements[j++] = reqq.elements[i]; |
355 | reqq.count = j; |
356 | } |
357 | if (!reqq.count) |
358 | continue; |
359 | for (i = 0; i < reqq.count; i++) |
360 | { |
361 | p2 = reqq.elements[i]; |
362 | if (pool->solvables[p2].repo != installed) |
363 | { |
364 | /* all elements of reqq are installs, thus have different TEs */ |
365 | if (pool->solvables[p].repo != installed) |
366 | { |
367 | #if 0 |
368 | printf("add inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2)); |
369 | #endif |
370 | addedge(od, p, p2, pre); |
371 | } |
372 | else |
373 | { |
374 | #if 0 |
375 | printf("add uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2)); |
376 | #endif |
377 | addedge(od, p, p2, pre == TYPE_PREREQ(1<<5) ? TYPE_PREREQ_P(1<<3) : TYPE_REQ_P(1<<2)); |
378 | } |
379 | } |
380 | else |
381 | { |
382 | if (s->repo != installed) |
383 | continue; /* no inst->uninst edges, please! */ |
384 | |
385 | /* uninst -> uninst edge. Those make trouble. Only add if we must */ |
386 | if (trans->transaction_installed[p - installed->start] && !havescripts(pool, p)) |
387 | { |
388 | /* p is obsoleted by another package and has no scripts */ |
389 | /* we assume that the obsoletor is good enough to replace p */ |
390 | continue; |
391 | } |
392 | #if 0 |
393 | printf("add uninst->uninst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2)); |
394 | #endif |
395 | addedge(od, p2, p, pre == TYPE_PREREQ(1<<5) ? TYPE_PREREQ_P(1<<3) : TYPE_REQ_P(1<<2)); |
396 | } |
397 | } |
398 | } |
399 | } |
400 | if (s->conflicts) |
401 | { |
402 | conp = s->repo->idarraydata + s->conflicts; |
403 | while ((con = *conp++) != 0) |
404 | { |
405 | FOR_PROVIDES(p2, pp2, con)for (pp2 = pool_whatprovides(pool, con) ; (p2 = pool->whatprovidesdata [pp2++]) != 0; ) |
406 | { |
407 | if (p2 == p) |
408 | continue; |
409 | s2 = pool->solvables + p2; |
410 | if (!s2->repo) |
411 | continue; |
412 | if (s->repo == installed) |
413 | { |
414 | if (s2->repo != installed && MAPTST(&trans->transactsmap, p2)((&trans->transactsmap)->map[(p2) >> 3] & (1 << ((p2) & 7)))) |
415 | { |
416 | /* deinstall p before installing p2 */ |
417 | #if 0 |
418 | printf("add conflict uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p2), pool_dep2str(pool, con), pool_solvid2str(pool, p)); |
419 | #endif |
420 | addedge(od, p2, p, TYPE_CON(1<<1)); |
421 | } |
422 | } |
423 | else |
424 | { |
425 | if (s2->repo == installed && MAPTST(&trans->transactsmap, p2)((&trans->transactsmap)->map[(p2) >> 3] & (1 << ((p2) & 7)))) |
426 | { |
427 | /* deinstall p2 before installing p */ |
428 | #if 0 |
429 | printf("add conflict uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, con), pool_solvid2str(pool, p2)); |
430 | #endif |
431 | addedge(od, p, p2, TYPE_CON(1<<1)); |
432 | } |
433 | } |
434 | |
435 | } |
436 | } |
437 | } |
438 | if (s->repo == installed && solvable_lookup_idarray(s, SOLVABLE_TRIGGERS, &reqq) && reqq.count) |
439 | { |
440 | /* we're getting deinstalled/updated. Try to do this before our |
441 | * triggers are hit */ |
442 | for (i = 0; i < reqq.count; i++) |
443 | { |
444 | Id tri = reqq.elements[i]; |
445 | FOR_PROVIDES(p2, pp2, tri)for (pp2 = pool_whatprovides(pool, tri) ; (p2 = pool->whatprovidesdata [pp2++]) != 0; ) |
446 | { |
447 | if (p2 == p) |
448 | continue; |
449 | s2 = pool->solvables + p2; |
450 | if (!s2->repo) |
451 | continue; |
452 | if (s2->name == s->name) |
453 | continue; /* obsoleted anyway */ |
454 | if (s2->repo != installed && MAPTST(&trans->transactsmap, p2)((&trans->transactsmap)->map[(p2) >> 3] & (1 << ((p2) & 7)))) |
455 | { |
456 | /* deinstall/update p before installing p2 */ |
457 | #if 0 |
458 | printf("add trigger uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p2), pool_dep2str(pool, tri), pool_solvid2str(pool, p)); |
459 | #endif |
460 | addedge(od, p2, p, TYPE_CON(1<<1)); |
461 | } |
462 | } |
463 | } |
464 | } |
465 | queue_free(&reqq); |
466 | } |
467 | |
468 | |
469 | /* break an edge in a cycle */ |
470 | static void |
471 | breakcycle(struct orderdata *od, Id *cycle) |
472 | { |
473 | Pool *pool = od->trans->pool; |
474 | Id ddegmin, ddegmax, ddeg; |
475 | int k, l; |
476 | struct _TransactionElement *te; |
477 | |
478 | l = 0; |
479 | ddegmin = ddegmax = 0; |
480 | for (k = 0; cycle[k + 1]; k += 2) |
481 | { |
482 | ddeg = od->edgedata[cycle[k + 1] + 1]; |
483 | if (ddeg > ddegmax) |
484 | ddegmax = ddeg; |
485 | if (!k || ddeg < ddegmin) |
486 | { |
487 | l = k; |
488 | ddegmin = ddeg; |
489 | continue; |
490 | } |
491 | if (ddeg == ddegmin) |
492 | { |
493 | if (havescripts(pool, od->tes[cycle[l]].p) && !havescripts(pool, od->tes[cycle[k]].p)) |
494 | { |
495 | /* prefer k, as l comes from a package with contains scriptlets */ |
496 | l = k; |
497 | continue; |
498 | } |
499 | /* same edge value, check for prereq */ |
500 | } |
501 | } |
502 | |
503 | /* record brkoen cycle starting with the tail */ |
504 | queue_push(&od->cycles, od->cyclesdata.count); /* offset into data */ |
505 | queue_push(&od->cycles, k / 2); /* cycle elements */ |
506 | queue_push(&od->cycles, od->edgedata[cycle[l + 1] + 1]); /* broken edge */ |
507 | queue_push(&od->cycles, (ddegmax << 16) | ddegmin); /* max/min values */ |
508 | od->ncycles++; |
509 | for (k = l;;) |
510 | { |
511 | k += 2; |
512 | if (!cycle[k + 1]) |
513 | k = 0; |
514 | queue_push(&od->cyclesdata, cycle[k]); |
515 | if (k == l) |
516 | break; |
517 | } |
518 | queue_push(&od->cyclesdata, 0); /* mark end */ |
519 | |
520 | /* break that edge */ |
521 | od->edgedata[cycle[l + 1] + 1] |= TYPE_BROKEN(1<<0); |
522 | |
523 | #if 1 |
524 | if (ddegmin < TYPE_REQ(1<<4)) |
525 | return; |
526 | #endif |
527 | |
528 | /* cycle recorded, print it */ |
529 | if (ddegmin >= TYPE_REQ(1<<4) && (ddegmax & TYPE_PREREQ(1<<5)) != 0) |
530 | POOL_DEBUG(SOLV_DEBUG_STATS, "CRITICAL ")do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "CRITICAL ");} while (0); |
531 | POOL_DEBUG(SOLV_DEBUG_STATS, "cycle: --> ")do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "cycle: --> ");} while (0); |
532 | for (k = 0; cycle[k + 1]; k += 2) |
533 | { |
534 | te = od->tes + cycle[k]; |
535 | if ((od->edgedata[cycle[k + 1] + 1] & TYPE_BROKEN(1<<0)) != 0) |
536 | POOL_DEBUG(SOLV_DEBUG_STATS, "%s ##%x##> ", pool_solvid2str(pool, te->p), od->edgedata[cycle[k + 1] + 1])do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "%s ##%x##> ", pool_solvid2str(pool , te->p), od->edgedata[cycle[k + 1] + 1]);} while (0); |
537 | else |
538 | POOL_DEBUG(SOLV_DEBUG_STATS, "%s --%x--> ", pool_solvid2str(pool, te->p), od->edgedata[cycle[k + 1] + 1])do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "%s --%x--> ", pool_solvid2str(pool , te->p), od->edgedata[cycle[k + 1] + 1]);} while (0); |
539 | } |
540 | POOL_DEBUG(SOLV_DEBUG_STATS, "\n")do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "\n");} while (0); |
541 | } |
542 | |
543 | static inline void |
544 | dump_tes(struct orderdata *od) |
545 | { |
546 | Pool *pool = od->trans->pool; |
547 | int i, j; |
548 | Queue obsq; |
549 | struct _TransactionElement *te, *te2; |
550 | |
551 | queue_init(&obsq); |
552 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
553 | { |
554 | Solvable *s = pool->solvables + te->p; |
555 | POOL_DEBUG(SOLV_DEBUG_RESULT, "TE %4d: %c%s\n", i, s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s))do {if ((pool->debugmask & ((1<<10))) != 0) pool_debug (pool, ((1<<10)), "TE %4d: %c%s\n", i, s->repo == pool ->installed ? '-' : '+', pool_solvable2str(pool, s));} while (0); |
556 | if (s->repo != pool->installed) |
557 | { |
558 | queue_empty(&obsq); |
559 | transaction_all_obs_pkgs(od->trans, te->p, &obsq); |
560 | for (j = 0; j < obsq.count; j++) |
561 | POOL_DEBUG(SOLV_DEBUG_RESULT, " -%s\n", pool_solvid2str(pool, obsq.elements[j]))do {if ((pool->debugmask & ((1<<10))) != 0) pool_debug (pool, ((1<<10)), " -%s\n", pool_solvid2str(pool , obsq.elements[j]));} while (0); |
562 | } |
563 | for (j = te->edges; od->edgedata[j]; j += 2) |
564 | { |
565 | te2 = od->tes + od->edgedata[j]; |
566 | if ((od->edgedata[j + 1] & TYPE_BROKEN(1<<0)) == 0) |
567 | POOL_DEBUG(SOLV_DEBUG_RESULT, " --%x--> TE %4d: %s\n", od->edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2->p))do {if ((pool->debugmask & ((1<<10))) != 0) pool_debug (pool, ((1<<10)), " --%x--> TE %4d: %s\n", od-> edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2 ->p));} while (0); |
568 | else |
569 | POOL_DEBUG(SOLV_DEBUG_RESULT, " ##%x##> TE %4d: %s\n", od->edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2->p))do {if ((pool->debugmask & ((1<<10))) != 0) pool_debug (pool, ((1<<10)), " ##%x##> TE %4d: %s\n", od-> edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2 ->p));} while (0); |
570 | } |
571 | } |
572 | } |
573 | |
574 | static void |
575 | reachable(struct orderdata *od, Id i) |
576 | { |
577 | struct _TransactionElement *te = od->tes + i; |
578 | int j, k; |
579 | |
580 | if (te->mark != 0) |
581 | return; |
582 | te->mark = 1; |
583 | for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2) |
584 | { |
585 | if ((od->edgedata[j + 1] & TYPE_BROKEN(1<<0)) != 0) |
586 | continue; |
587 | if (!od->tes[k].mark) |
588 | reachable(od, k); |
589 | if (od->tes[k].mark == 2) |
590 | { |
591 | te->mark = 2; |
592 | return; |
593 | } |
594 | } |
595 | te->mark = -1; |
596 | } |
597 | |
598 | static void |
599 | addcycleedges(struct orderdata *od, Id *cycle, Queue *todo) |
600 | { |
601 | #if 0 |
602 | Transaction *trans = od->trans; |
603 | Pool *pool = trans->pool; |
604 | #endif |
605 | struct _TransactionElement *te; |
606 | int i, j, k, tail; |
607 | int head; |
608 | |
609 | #if 0 |
610 | printf("addcycleedges\n"); |
611 | for (i = 0; (j = cycle[i]) != 0; i++) |
612 | printf("cycle %s\n", pool_solvid2str(pool, od->tes[j].p)); |
613 | #endif |
614 | |
615 | /* first add all the tail cycle edges */ |
616 | |
617 | /* see what we can reach from the cycle */ |
618 | queue_empty(todo); |
619 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
620 | te->mark = 0; |
621 | for (i = 0; (j = cycle[i]) != 0; i++) |
622 | { |
623 | od->tes[j].mark = -1; |
624 | queue_push(todo, j); |
625 | } |
626 | while (todo->count) |
627 | { |
628 | i = queue_pop(todo); |
629 | te = od->tes + i; |
630 | if (te->mark > 0) |
631 | continue; |
632 | te->mark = te->mark < 0 ? 2 : 1; |
633 | for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2) |
634 | { |
635 | if ((od->edgedata[j + 1] & TYPE_BROKEN(1<<0)) != 0) |
636 | continue; |
637 | if (od->tes[k].mark > 0) |
638 | continue; /* no need to visit again */ |
639 | queue_push(todo, k); |
640 | } |
641 | } |
642 | /* now all cycle TEs are marked with 2, all TEs reachable |
643 | * from the cycle are marked with 1 */ |
644 | tail = cycle[0]; |
645 | od->tes[tail].mark = 1; /* no need to add edges */ |
646 | |
647 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
648 | { |
649 | if (te->mark) |
650 | continue; /* reachable from cycle */ |
651 | for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2) |
652 | { |
653 | if ((od->edgedata[j + 1] & TYPE_BROKEN(1<<0)) != 0) |
654 | continue; |
655 | if (od->tes[k].mark != 2) |
656 | continue; |
657 | /* We found an edge to the cycle. Add an extra edge to the tail */ |
658 | /* the TE was not reachable, so we're not creating a new cycle! */ |
659 | #if 0 |
660 | printf("adding TO TAIL cycle edge %d->%d %s->%s!\n", i, tail, pool_solvid2str(pool, od->tes[i].p), pool_solvid2str(pool, od->tes[tail].p)); |
661 | #endif |
662 | j -= te->edges; /* in case we move */ |
663 | addteedge(od, i, tail, TYPE_CYCLETAIL(1<<16)); |
664 | j += te->edges; |
Value stored to 'j' is never read | |
665 | break; /* one edge is enough */ |
666 | } |
667 | } |
668 | |
669 | /* now add all head cycle edges */ |
670 | |
671 | /* reset marks */ |
672 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
673 | te->mark = 0; |
674 | head = 0; |
675 | for (i = 0; (j = cycle[i]) != 0; i++) |
676 | { |
677 | head = j; |
678 | od->tes[j].mark = 2; |
679 | } |
680 | /* first the head to save some time */ |
681 | te = od->tes + head; |
682 | for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2) |
683 | { |
684 | if ((od->edgedata[j + 1] & TYPE_BROKEN(1<<0)) != 0) |
685 | continue; |
686 | if (!od->tes[k].mark) |
687 | reachable(od, k); |
688 | if (od->tes[k].mark == -1) |
689 | od->tes[k].mark = -2; /* no need for another edge */ |
690 | } |
691 | for (i = 0; cycle[i] != 0; i++) |
692 | { |
693 | if (cycle[i] == head) |
694 | break; |
695 | te = od->tes + cycle[i]; |
696 | for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2) |
697 | { |
698 | if ((od->edgedata[j + 1] & TYPE_BROKEN(1<<0)) != 0) |
699 | continue; |
700 | /* see if we can reach a cycle TE from k */ |
701 | if (!od->tes[k].mark) |
702 | reachable(od, k); |
703 | if (od->tes[k].mark == -1) |
704 | { |
705 | #if 0 |
706 | printf("adding FROM HEAD cycle edge %d->%d %s->%s [%s]!\n", head, k, pool_solvid2str(pool, od->tes[head].p), pool_solvid2str(pool, od->tes[k].p), pool_solvid2str(pool, od->tes[cycle[i]].p)); |
707 | #endif |
708 | addteedge(od, head, k, TYPE_CYCLEHEAD(1<<17)); |
709 | od->tes[k].mark = -2; /* no need to add that one again */ |
710 | } |
711 | } |
712 | } |
713 | } |
714 | |
715 | void |
716 | transaction_order(Transaction *trans, int flags) |
717 | { |
718 | Pool *pool = trans->pool; |
719 | Queue *tr = &trans->steps; |
720 | Repo *installed = pool->installed; |
721 | Id p; |
722 | Solvable *s; |
723 | int i, j, k, numte, numedge; |
724 | struct orderdata od; |
725 | struct _TransactionElement *te; |
726 | Queue todo, obsq, samerepoq, uninstq; |
727 | int cycstart, cycel; |
728 | Id *cycle; |
729 | int oldcount; |
730 | int start, now; |
731 | Repo *lastrepo; |
732 | int lastmedia; |
733 | Id *temedianr; |
734 | |
735 | start = now = solv_timems(0); |
736 | POOL_DEBUG(SOLV_DEBUG_STATS, "ordering transaction\n")do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "ordering transaction\n");} while (0); |
737 | /* free old data if present */ |
738 | if (trans->orderdata) |
739 | { |
740 | struct _TransactionOrderdata *od = trans->orderdata; |
741 | od->tes = solv_free(od->tes); |
742 | od->invedgedata = solv_free(od->invedgedata); |
743 | trans->orderdata = solv_free(trans->orderdata); |
744 | } |
745 | |
746 | /* create a transaction element for every active component */ |
747 | numte = 0; |
748 | for (i = 0; i < tr->count; i++) |
749 | { |
750 | p = tr->elements[i]; |
751 | s = pool->solvables + p; |
752 | if (installed && s->repo == installed && trans->transaction_installed[p - installed->start]) |
753 | continue; |
754 | numte++; |
755 | } |
756 | POOL_DEBUG(SOLV_DEBUG_STATS, "transaction elements: %d\n", numte)do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "transaction elements: %d\n", numte);} while (0); |
757 | if (!numte) |
758 | return; /* nothing to do... */ |
759 | |
760 | numte++; /* leave first one zero */ |
761 | memset(&od, 0, sizeof(od)); |
762 | od.trans = trans; |
763 | od.ntes = numte; |
764 | od.tes = solv_calloc(numte, sizeof(*od.tes)); |
765 | od.edgedata = solv_extend(0, 0, 1, sizeof(Id), EDGEDATA_BLOCK127); |
766 | od.edgedata[0] = 0; |
767 | od.nedgedata = 1; |
768 | queue_init(&od.cycles); |
769 | |
770 | /* initialize TEs */ |
771 | for (i = 0, te = od.tes + 1; i < tr->count; i++) |
772 | { |
773 | p = tr->elements[i]; |
774 | s = pool->solvables + p; |
775 | if (installed && s->repo == installed && trans->transaction_installed[p - installed->start]) |
776 | continue; |
777 | te->p = p; |
778 | te++; |
779 | } |
780 | |
781 | /* create dependency graph */ |
782 | for (i = 0; i < tr->count; i++) |
783 | addsolvableedges(&od, pool->solvables + tr->elements[i]); |
784 | |
785 | /* count edges */ |
786 | numedge = 0; |
787 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
788 | for (j = te->edges; od.edgedata[j]; j += 2) |
789 | numedge++; |
790 | POOL_DEBUG(SOLV_DEBUG_STATS, "edges: %d, edge space: %d\n", numedge, od.nedgedata / 2)do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "edges: %d, edge space: %d\n", numedge , od.nedgedata / 2);} while (0); |
791 | POOL_DEBUG(SOLV_DEBUG_STATS, "edge creation took %d ms\n", solv_timems(now))do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "edge creation took %d ms\n", solv_timems (now));} while (0); |
792 | |
793 | #if 0 |
794 | dump_tes(&od); |
795 | #endif |
796 | |
797 | now = solv_timems(0); |
798 | /* kill all cycles */ |
799 | queue_init(&todo); |
800 | for (i = numte - 1; i > 0; i--) |
801 | queue_push(&todo, i); |
802 | |
803 | while (todo.count) |
804 | { |
805 | i = queue_pop(&todo); |
806 | /* printf("- look at TE %d\n", i); */ |
807 | if (i < 0) |
808 | { |
809 | i = -i; |
810 | od.tes[i].mark = 2; /* done with that one */ |
811 | continue; |
812 | } |
813 | te = od.tes + i; |
814 | if (te->mark == 2) |
815 | continue; /* already finished before */ |
816 | if (te->mark == 0) |
817 | { |
818 | int edgestovisit = 0; |
819 | /* new node, visit edges */ |
820 | for (j = te->edges; (k = od.edgedata[j]) != 0; j += 2) |
821 | { |
822 | if ((od.edgedata[j + 1] & TYPE_BROKEN(1<<0)) != 0) |
823 | continue; |
824 | if (od.tes[k].mark == 2) |
825 | continue; /* no need to visit again */ |
826 | if (!edgestovisit++) |
827 | queue_push(&todo, -i); /* end of edges marker */ |
828 | queue_push(&todo, k); |
829 | } |
830 | if (!edgestovisit) |
831 | te->mark = 2; /* no edges, done with that one */ |
832 | else |
833 | te->mark = 1; /* under investigation */ |
834 | continue; |
835 | } |
836 | /* oh no, we found a cycle */ |
837 | /* find start of cycle node (<0) */ |
838 | for (j = todo.count - 1; j >= 0; j--) |
839 | if (todo.elements[j] == -i) |
840 | break; |
841 | assert(j >= 0)({ if (j >= 0) ; else __assert_fail ("j >= 0", "/home/brain/Projects/upstream/libsolv/src/order.c" , 841, __PRETTY_FUNCTION__); }); |
842 | cycstart = j; |
843 | /* build te/edge chain */ |
844 | k = cycstart; |
845 | for (j = k; j < todo.count; j++) |
846 | if (todo.elements[j] < 0) |
847 | todo.elements[k++] = -todo.elements[j]; |
848 | cycel = k - cycstart; |
849 | assert(cycel > 1)({ if (cycel > 1) ; else __assert_fail ("cycel > 1", "/home/brain/Projects/upstream/libsolv/src/order.c" , 849, __PRETTY_FUNCTION__); }); |
850 | /* make room for edges, two extra element for cycle loop + terminating 0 */ |
851 | while (todo.count < cycstart + 2 * cycel + 2) |
852 | queue_push(&todo, 0); |
853 | cycle = todo.elements + cycstart; |
854 | cycle[cycel] = i; /* close the loop */ |
855 | cycle[2 * cycel + 1] = 0; /* terminator */ |
856 | for (k = cycel; k > 0; k--) |
857 | { |
858 | cycle[k * 2] = cycle[k]; |
859 | te = od.tes + cycle[k - 1]; |
860 | assert(te->mark == 1)({ if (te->mark == 1) ; else __assert_fail ("te->mark == 1" , "/home/brain/Projects/upstream/libsolv/src/order.c", 860, __PRETTY_FUNCTION__ ); }); |
861 | te->mark = 0; /* reset investigation marker */ |
862 | /* printf("searching for edge from %d to %d\n", cycle[k - 1], cycle[k]); */ |
863 | for (j = te->edges; od.edgedata[j]; j += 2) |
864 | if (od.edgedata[j] == cycle[k]) |
865 | break; |
866 | assert(od.edgedata[j])({ if (od.edgedata[j]) ; else __assert_fail ("od.edgedata[j]" , "/home/brain/Projects/upstream/libsolv/src/order.c", 866, __PRETTY_FUNCTION__ ); }); |
867 | cycle[k * 2 - 1] = j; |
868 | } |
869 | /* now cycle looks like this: */ |
870 | /* te1 edge te2 edge te3 ... teN edge te1 0 */ |
871 | breakcycle(&od, cycle); |
872 | /* restart with start of cycle */ |
873 | todo.count = cycstart + 1; |
874 | } |
875 | POOL_DEBUG(SOLV_DEBUG_STATS, "cycles broken: %d\n", od.ncycles)do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "cycles broken: %d\n", od.ncycles);} while (0); |
876 | POOL_DEBUG(SOLV_DEBUG_STATS, "cycle breaking took %d ms\n", solv_timems(now))do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "cycle breaking took %d ms\n", solv_timems (now));} while (0); |
877 | |
878 | now = solv_timems(0); |
879 | /* now go through all broken cycles and create cycle edges to help |
880 | the ordering */ |
881 | for (i = od.cycles.count - 4; i >= 0; i -= 4) |
882 | { |
883 | if (od.cycles.elements[i + 2] >= TYPE_REQ(1<<4)) |
884 | addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo); |
885 | } |
886 | for (i = od.cycles.count - 4; i >= 0; i -= 4) |
887 | { |
888 | if (od.cycles.elements[i + 2] < TYPE_REQ(1<<4)) |
889 | addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo); |
890 | } |
891 | POOL_DEBUG(SOLV_DEBUG_STATS, "cycle edge creation took %d ms\n", solv_timems(now))do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "cycle edge creation took %d ms\n", solv_timems (now));} while (0); |
892 | |
893 | #if 0 |
894 | dump_tes(&od); |
895 | #endif |
896 | /* all edges are finally set up and there are no cycles, now the easy part. |
897 | * Create an ordered transaction */ |
898 | now = solv_timems(0); |
899 | /* first invert all edges */ |
900 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
901 | te->mark = 1; /* term 0 */ |
902 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
903 | { |
904 | for (j = te->edges; od.edgedata[j]; j += 2) |
905 | { |
906 | if ((od.edgedata[j + 1] & TYPE_BROKEN(1<<0)) != 0) |
907 | continue; |
908 | od.tes[od.edgedata[j]].mark++; |
909 | } |
910 | } |
911 | j = 1; |
912 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
913 | { |
914 | te->mark += j; |
915 | j = te->mark; |
916 | } |
917 | POOL_DEBUG(SOLV_DEBUG_STATS, "invedge space: %d\n", j + 1)do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "invedge space: %d\n", j + 1);} while ( 0); |
918 | od.invedgedata = solv_calloc(j + 1, sizeof(Id)); |
919 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
920 | { |
921 | for (j = te->edges; od.edgedata[j]; j += 2) |
922 | { |
923 | if ((od.edgedata[j + 1] & TYPE_BROKEN(1<<0)) != 0) |
924 | continue; |
925 | od.invedgedata[--od.tes[od.edgedata[j]].mark] = i; |
926 | } |
927 | } |
928 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
929 | te->edges = te->mark; /* edges now points into invedgedata */ |
930 | od.edgedata = solv_free(od.edgedata); |
931 | od.nedgedata = j + 1; |
932 | |
933 | /* now the final ordering */ |
934 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
935 | te->mark = 0; |
936 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
937 | for (j = te->edges; od.invedgedata[j]; j++) |
938 | od.tes[od.invedgedata[j]].mark++; |
939 | |
940 | queue_init(&samerepoq); |
941 | queue_init(&uninstq); |
942 | queue_empty(&todo); |
943 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
944 | if (te->mark == 0) |
945 | { |
946 | if (installed && pool->solvables[te->p].repo == installed) |
947 | queue_push(&uninstq, i); |
948 | else |
949 | queue_push(&todo, i); |
950 | } |
951 | assert(todo.count > 0 || uninstq.count > 0)({ if (todo.count > 0 || uninstq.count > 0) ; else __assert_fail ("todo.count > 0 || uninstq.count > 0", "/home/brain/Projects/upstream/libsolv/src/order.c" , 951, __PRETTY_FUNCTION__); }); |
952 | oldcount = tr->count; |
953 | queue_empty(tr); |
954 | |
955 | queue_init(&obsq); |
956 | |
957 | lastrepo = 0; |
958 | lastmedia = 0; |
959 | temedianr = solv_calloc(numte, sizeof(Id)); |
960 | for (i = 1; i < numte; i++) |
961 | { |
962 | Solvable *s = pool->solvables + od.tes[i].p; |
963 | if (installed && s->repo == installed) |
964 | j = 1; |
965 | else |
966 | j = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1); |
967 | temedianr[i] = j; |
968 | } |
969 | for (;;) |
970 | { |
971 | /* select an TE i */ |
972 | if (uninstq.count) |
973 | i = queue_shift(&uninstq); |
974 | else if (samerepoq.count) |
975 | i = queue_shift(&samerepoq); |
976 | else if (todo.count) |
977 | { |
978 | /* find next repo/media */ |
979 | for (j = 0; j < todo.count; j++) |
980 | { |
981 | if (!j || temedianr[todo.elements[j]] < lastmedia) |
982 | { |
983 | i = j; |
984 | lastmedia = temedianr[todo.elements[j]]; |
985 | } |
986 | } |
987 | lastrepo = pool->solvables[od.tes[todo.elements[i]].p].repo; |
988 | |
989 | /* move all matching TEs to samerepoq */ |
990 | for (i = j = 0; j < todo.count; j++) |
991 | { |
992 | int k = todo.elements[j]; |
993 | if (temedianr[k] == lastmedia && pool->solvables[od.tes[k].p].repo == lastrepo) |
994 | queue_push(&samerepoq, k); |
995 | else |
996 | todo.elements[i++] = k; |
997 | } |
998 | todo.count = i; |
999 | |
1000 | assert(samerepoq.count)({ if (samerepoq.count) ; else __assert_fail ("samerepoq.count" , "/home/brain/Projects/upstream/libsolv/src/order.c", 1000, __PRETTY_FUNCTION__ ); }); |
1001 | i = queue_shift(&samerepoq); |
1002 | } |
1003 | else |
1004 | break; |
1005 | |
1006 | te = od.tes + i; |
1007 | queue_push(tr, te->p); |
1008 | #if 0 |
1009 | printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]); |
1010 | #endif |
1011 | s = pool->solvables + te->p; |
1012 | for (j = te->edges; od.invedgedata[j]; j++) |
1013 | { |
1014 | struct _TransactionElement *te2 = od.tes + od.invedgedata[j]; |
1015 | assert(te2->mark > 0)({ if (te2->mark > 0) ; else __assert_fail ("te2->mark > 0" , "/home/brain/Projects/upstream/libsolv/src/order.c", 1015, __PRETTY_FUNCTION__ ); }); |
1016 | if (--te2->mark == 0) |
1017 | { |
1018 | Solvable *s = pool->solvables + te2->p; |
1019 | #if 0 |
1020 | printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata[j]]); |
1021 | #endif |
1022 | if (installed && s->repo == installed) |
1023 | queue_push(&uninstq, od.invedgedata[j]); |
1024 | else if (s->repo == lastrepo && temedianr[od.invedgedata[j]] == lastmedia) |
1025 | queue_push(&samerepoq, od.invedgedata[j]); |
1026 | else |
1027 | queue_push(&todo, od.invedgedata[j]); |
1028 | } |
1029 | } |
1030 | } |
1031 | solv_free(temedianr); |
1032 | queue_free(&todo); |
1033 | queue_free(&samerepoq); |
1034 | queue_free(&uninstq); |
1035 | queue_free(&obsq); |
1036 | for (i = 1, te = od.tes + i; i < numte; i++, te++) |
1037 | assert(te->mark == 0)({ if (te->mark == 0) ; else __assert_fail ("te->mark == 0" , "/home/brain/Projects/upstream/libsolv/src/order.c", 1037, __PRETTY_FUNCTION__ ); }); |
1038 | |
1039 | /* add back obsoleted packages */ |
1040 | transaction_add_obsoleted(trans); |
1041 | assert(tr->count == oldcount)({ if (tr->count == oldcount) ; else __assert_fail ("tr->count == oldcount" , "/home/brain/Projects/upstream/libsolv/src/order.c", 1041, __PRETTY_FUNCTION__ ); }); |
1042 | |
1043 | POOL_DEBUG(SOLV_DEBUG_STATS, "creating new transaction took %d ms\n", solv_timems(now))do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "creating new transaction took %d ms\n" , solv_timems(now));} while (0); |
1044 | POOL_DEBUG(SOLV_DEBUG_STATS, "transaction ordering took %d ms\n", solv_timems(start))do {if ((pool->debugmask & ((1<<3))) != 0) pool_debug (pool, ((1<<3)), "transaction ordering took %d ms\n", solv_timems (start));} while (0); |
1045 | |
1046 | if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA(1 << 0) | SOLVER_TRANSACTION_KEEP_ORDERCYCLES(1 << 1))) != 0) |
1047 | { |
1048 | struct _TransactionOrderdata *tod; |
1049 | trans->orderdata = tod = solv_calloc(1, sizeof(*trans->orderdata)); |
1050 | if ((flags & SOLVER_TRANSACTION_KEEP_ORDERCYCLES(1 << 1)) != 0) |
1051 | { |
1052 | Queue *cycles = tod->cycles = solv_calloc(1, sizeof(Queue)); |
1053 | queue_init_clone(cycles, &od.cyclesdata); |
1054 | /* map from tes to packages */ |
1055 | for (i = 0; i < cycles->count; i++) |
1056 | if (cycles->elements[i]) |
1057 | cycles->elements[i] = od.tes[cycles->elements[i]].p; |
1058 | queue_insertn(cycles, cycles->count, od.cycles.count, od.cycles.elements); |
1059 | queue_push(cycles, od.cycles.count / 4); |
1060 | } |
1061 | if ((flags & SOLVER_TRANSACTION_KEEP_ORDERDATA(1 << 0)) != 0) |
1062 | { |
1063 | tod->tes = od.tes; |
1064 | tod->ntes = numte; |
1065 | tod->invedgedata = od.invedgedata; |
1066 | tod->ninvedgedata = od.nedgedata; |
1067 | od.tes = 0; |
1068 | od.invedgedata = 0; |
1069 | } |
1070 | } |
1071 | solv_free(od.tes); |
1072 | solv_free(od.invedgedata); |
1073 | queue_free(&od.cycles); |
1074 | queue_free(&od.cyclesdata); |
1075 | } |
1076 | |
1077 | |
1078 | int |
1079 | transaction_order_add_choices(Transaction *trans, Id chosen, Queue *choices) |
1080 | { |
1081 | int i, j; |
1082 | struct _TransactionOrderdata *od = trans->orderdata; |
1083 | struct _TransactionElement *te; |
1084 | |
1085 | if (!od) |
1086 | return choices->count; |
1087 | if (!chosen) |
1088 | { |
1089 | /* initialization step */ |
1090 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
1091 | te->mark = 0; |
1092 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
1093 | { |
1094 | for (j = te->edges; od->invedgedata[j]; j++) |
1095 | od->tes[od->invedgedata[j]].mark++; |
1096 | } |
1097 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
1098 | if (!te->mark) |
1099 | queue_push(choices, te->p); |
1100 | return choices->count; |
1101 | } |
1102 | for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) |
1103 | if (te->p == chosen) |
1104 | break; |
1105 | if (i == od->ntes) |
1106 | return choices->count; |
1107 | if (te->mark > 0) |
1108 | { |
1109 | /* hey! out-of-order installation! */ |
1110 | te->mark = -1; |
1111 | } |
1112 | for (j = te->edges; od->invedgedata[j]; j++) |
1113 | { |
1114 | te = od->tes + od->invedgedata[j]; |
1115 | assert(te->mark > 0 || te->mark == -1)({ if (te->mark > 0 || te->mark == -1) ; else __assert_fail ("te->mark > 0 || te->mark == -1", "/home/brain/Projects/upstream/libsolv/src/order.c" , 1115, __PRETTY_FUNCTION__); }); |
1116 | if (te->mark > 0 && --te->mark == 0) |
1117 | queue_push(choices, te->p); |
1118 | } |
1119 | return choices->count; |
1120 | } |
1121 | |
1122 | void |
1123 | transaction_add_obsoleted(Transaction *trans) |
1124 | { |
1125 | Pool *pool = trans->pool; |
1126 | Repo *installed = pool->installed; |
1127 | Id p; |
1128 | Solvable *s; |
1129 | int i, j, k, max; |
1130 | Map done; |
1131 | Queue obsq, *steps; |
1132 | |
1133 | if (!installed || !trans->steps.count) |
1134 | return; |
1135 | /* calculate upper bound */ |
1136 | max = 0; |
1137 | FOR_REPO_SOLVABLES(installed, p, s)for (p = (installed)->start, s = (installed)->pool-> solvables + p; p < (installed)->end; p++, s = (installed )->pool->solvables + p) if (s->repo != (installed)) continue ; else |
1138 | if (MAPTST(&trans->transactsmap, p)((&trans->transactsmap)->map[(p) >> 3] & ( 1 << ((p) & 7)))) |
1139 | max++; |
1140 | if (!max) |
1141 | return; |
1142 | /* make room */ |
1143 | steps = &trans->steps; |
1144 | queue_insertn(steps, 0, max, 0); |
1145 | |
1146 | /* now add em */ |
1147 | map_init(&done, installed->end - installed->start); |
1148 | queue_init(&obsq); |
1149 | for (j = 0, i = max; i < steps->count; i++) |
1150 | { |
1151 | p = trans->steps.elements[i]; |
1152 | if (pool->solvables[p].repo == installed) |
1153 | { |
1154 | if (!trans->transaction_installed[p - pool->installed->start]) |
1155 | trans->steps.elements[j++] = p; |
1156 | continue; |
1157 | } |
1158 | trans->steps.elements[j++] = p; |
1159 | queue_empty(&obsq); |
1160 | transaction_all_obs_pkgs(trans, p, &obsq); |
1161 | for (k = 0; k < obsq.count; k++) |
1162 | { |
1163 | p = obsq.elements[k]; |
1164 | assert(p >= installed->start && p < installed->end)({ if (p >= installed->start && p < installed ->end) ; else __assert_fail ("p >= installed->start && p < installed->end" , "/home/brain/Projects/upstream/libsolv/src/order.c", 1164, __PRETTY_FUNCTION__ ); }); |
1165 | if (!MAPTST(&trans->transactsmap, p)((&trans->transactsmap)->map[(p) >> 3] & ( 1 << ((p) & 7)))) /* just in case */ |
1166 | continue; |
1167 | if (MAPTST(&done, p - installed->start)((&done)->map[(p - installed->start) >> 3] & (1 << ((p - installed->start) & 7)))) |
1168 | continue; |
1169 | MAPSET(&done, p - installed->start)((&done)->map[(p - installed->start) >> 3] |= 1 << ((p - installed->start) & 7)); |
1170 | trans->steps.elements[j++] = p; |
1171 | } |
1172 | } |
1173 | |
1174 | /* free unneeded space */ |
1175 | queue_truncate(steps, j); |
1176 | map_free(&done); |
1177 | queue_free(&obsq); |
1178 | } |
1179 | |
1180 | static void |
1181 | transaction_check_pkg(Transaction *trans, Id tepkg, Id pkg, Map *ins, Map *seen, int onlyprereq, Id noconfpkg, int depth) |
1182 | { |
1183 | Pool *pool = trans->pool; |
1184 | Id p, pp; |
1185 | Solvable *s; |
1186 | int good; |
1187 | |
1188 | if (MAPTST(seen, pkg)((seen)->map[(pkg) >> 3] & (1 << ((pkg) & 7)))) |
1189 | return; |
1190 | MAPSET(seen, pkg)((seen)->map[(pkg) >> 3] |= 1 << ((pkg) & 7 )); |
1191 | s = pool->solvables + pkg; |
1192 | #if 0 |
1193 | printf("- %*s%c%s\n", depth * 2, "", s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s)); |
1194 | #endif |
1195 | if (s->requires) |
1196 | { |
1197 | Id req, *reqp; |
1198 | int inpre = 0; |
1199 | reqp = s->repo->idarraydata + s->requires; |
1200 | while ((req = *reqp++) != 0) |
1201 | { |
1202 | if (req == SOLVABLE_PREREQMARKER) |
1203 | { |
1204 | inpre = 1; |
1205 | continue; |
1206 | } |
1207 | if (onlyprereq && !inpre) |
1208 | continue; |
1209 | if (!strncmp(pool_id2str(pool, req), "rpmlib(", 7)) |
1210 | continue; |
1211 | good = 0; |
1212 | /* first check kept packages, then freshly installed, then not yet uninstalled */ |
1213 | FOR_PROVIDES(p, pp, req)for (pp = pool_whatprovides(pool, req) ; (p = pool->whatprovidesdata [pp++]) != 0; ) |
1214 | { |
1215 | if (!MAPTST(ins, p)((ins)->map[(p) >> 3] & (1 << ((p) & 7 )))) |
1216 | continue; |
1217 | if (MAPTST(&trans->transactsmap, p)((&trans->transactsmap)->map[(p) >> 3] & ( 1 << ((p) & 7)))) |
1218 | continue; |
1219 | good++; |
1220 | transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1); |
1221 | } |
1222 | if (!good) |
1223 | { |
1224 | FOR_PROVIDES(p, pp, req)for (pp = pool_whatprovides(pool, req) ; (p = pool->whatprovidesdata [pp++]) != 0; ) |
1225 | { |
1226 | if (!MAPTST(ins, p)((ins)->map[(p) >> 3] & (1 << ((p) & 7 )))) |
1227 | continue; |
1228 | if (pool->solvables[p].repo == pool->installed) |
1229 | continue; |
1230 | good++; |
1231 | transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1); |
1232 | } |
1233 | } |
1234 | if (!good) |
1235 | { |
1236 | FOR_PROVIDES(p, pp, req)for (pp = pool_whatprovides(pool, req) ; (p = pool->whatprovidesdata [pp++]) != 0; ) |
1237 | { |
1238 | if (!MAPTST(ins, p)((ins)->map[(p) >> 3] & (1 << ((p) & 7 )))) |
1239 | continue; |
1240 | good++; |
1241 | transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1); |
1242 | } |
1243 | } |
1244 | if (!good) |
1245 | { |
1246 | POOL_DEBUG(SOLV_DEBUG_RESULT, " %c%s: nothing provides %s needed by %c%s\n", pool->solvables[tepkg].repo == pool->installed ? '-' : '+', pool_solvid2str(pool, tepkg), pool_dep2str(pool, req), s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s))do {if ((pool->debugmask & ((1<<10))) != 0) pool_debug (pool, ((1<<10)), " %c%s: nothing provides %s needed by %c%s\n" , pool->solvables[tepkg].repo == pool->installed ? '-' : '+', pool_solvid2str(pool, tepkg), pool_dep2str(pool, req), s ->repo == pool->installed ? '-' : '+', pool_solvable2str (pool, s));} while (0); |
1247 | } |
1248 | } |
1249 | } |
1250 | } |
1251 | |
1252 | void |
1253 | transaction_check_order(Transaction *trans) |
1254 | { |
1255 | Pool *pool = trans->pool; |
1256 | Solvable *s; |
1257 | Id p, lastins; |
1258 | Map ins, seen; |
1259 | int i; |
1260 | |
1261 | POOL_DEBUG(SOLV_DEBUG_RESULT, "\nchecking transaction order...\n")do {if ((pool->debugmask & ((1<<10))) != 0) pool_debug (pool, ((1<<10)), "\nchecking transaction order...\n"); } while (0); |
1262 | map_init(&ins, pool->nsolvables); |
1263 | map_init(&seen, pool->nsolvables); |
1264 | if (pool->installed) |
1265 | { |
1266 | FOR_REPO_SOLVABLES(pool->installed, p, s)for (p = (pool->installed)->start, s = (pool->installed )->pool->solvables + p; p < (pool->installed)-> end; p++, s = (pool->installed)->pool->solvables + p ) if (s->repo != (pool->installed)) continue; else |
1267 | MAPSET(&ins, p)((&ins)->map[(p) >> 3] |= 1 << ((p) & 7 )); |
1268 | } |
1269 | lastins = 0; |
1270 | for (i = 0; i < trans->steps.count; i++) |
1271 | { |
1272 | p = trans->steps.elements[i]; |
1273 | s = pool->solvables + p; |
1274 | if (s->repo != pool->installed) |
1275 | lastins = p; |
1276 | if (s->repo != pool->installed) |
1277 | MAPSET(&ins, p)((&ins)->map[(p) >> 3] |= 1 << ((p) & 7 )); |
1278 | if (havescripts(pool, p)) |
1279 | { |
1280 | MAPZERO(&seen)(memset((&seen)->map, 0, (&seen)->size)); |
1281 | transaction_check_pkg(trans, p, p, &ins, &seen, 1, lastins, 0); |
1282 | } |
1283 | if (s->repo == pool->installed) |
1284 | MAPCLR(&ins, p)((&ins)->map[(p) >> 3] &= ~(1 << ((p) & 7))); |
1285 | } |
1286 | map_free(&seen); |
1287 | map_free(&ins); |
1288 | POOL_DEBUG(SOLV_DEBUG_RESULT, "transaction order check done.\n")do {if ((pool->debugmask & ((1<<10))) != 0) pool_debug (pool, ((1<<10)), "transaction order check done.\n");} while (0); |
1289 | } |
1290 | |
1291 | void |
1292 | transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity) |
1293 | { |
1294 | struct _TransactionOrderdata *od = trans->orderdata; |
1295 | Queue *cq; |
1296 | int i, cid, ncycles; |
1297 | |
1298 | queue_empty(q); |
1299 | if (!od || !od->cycles || !od->cycles->count) |
1300 | return; |
1301 | cq = od->cycles; |
1302 | ncycles = cq->elements[cq->count - 1]; |
1303 | i = cq->count - 1 - ncycles * 4; |
1304 | for (cid = 1; cid <= ncycles; cid++, i += 4) |
1305 | { |
1306 | if (minseverity) |
1307 | { |
1308 | int cmin = cq->elements[i + 3] & 0xffff; |
1309 | int cmax = (cq->elements[i + 3] >> 16) & 0xffff; |
1310 | if (minseverity >= SOLVER_ORDERCYCLE_NORMAL1 && cmin < TYPE_REQ(1<<4)) |
1311 | continue; |
1312 | if (minseverity >= SOLVER_ORDERCYCLE_CRITICAL2 && (cmax & TYPE_PREREQ(1<<5)) == 0) |
1313 | continue; |
1314 | } |
1315 | queue_push(q, cid); |
1316 | } |
1317 | } |
1318 | |
1319 | int |
1320 | transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q) |
1321 | { |
1322 | struct _TransactionOrderdata *od = trans->orderdata; |
1323 | Queue *cq; |
1324 | int cmin, cmax, severity; |
1325 | int ncycles; |
1326 | |
1327 | queue_empty(q); |
1328 | if (!od || !od->cycles || !od->cycles->count) |
1329 | return SOLVER_ORDERCYCLE_HARMLESS0; |
1330 | cq = od->cycles; |
1331 | ncycles = cq->elements[cq->count - 1]; |
1332 | if (cid < 1 || cid > ncycles) |
1333 | return SOLVER_ORDERCYCLE_HARMLESS0; |
1334 | cid = cq->count - 1 - 4 * (ncycles - cid + 1); |
1335 | cmin = cq->elements[cid + 3] & 0xffff; |
1336 | cmax = (cq->elements[cid + 3] >> 16) & 0xffff; |
1337 | if (cmin < TYPE_REQ(1<<4)) |
1338 | severity = SOLVER_ORDERCYCLE_HARMLESS0; |
1339 | else if ((cmax & TYPE_PREREQ(1<<5)) == 0) |
1340 | severity = SOLVER_ORDERCYCLE_NORMAL1; |
1341 | else |
1342 | severity = SOLVER_ORDERCYCLE_CRITICAL2; |
1343 | if (q) |
1344 | queue_insertn(q, 0, cq->elements[cid + 1], cq->elements + cq->elements[cid]); |
1345 | return severity; |
1346 | } |
1347 |