2 * Copyright (c) 2007-2015, SUSE LLC
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Transaction ordering
20 #include "transaction.h"
26 struct s_TransactionElement {
27 Id p; /* solvable id */
28 Id edges; /* pointer into edges data */
32 struct s_TransactionOrderdata {
33 struct s_TransactionElement *tes;
38 Queue *edgedataq; /* from SOLVER_TRANSACTION_KEEP_ORDEREDGES */
41 #define TYPE_BROKEN (1<<0)
42 #define TYPE_CON (1<<1)
45 #define TYPE_REQ_UI (1<<4)
46 #define TYPE_PREREQ_UI (1<<5)
47 #define TYPE_REQ_UU (1<<6)
48 #define TYPE_PREREQ_UU (1<<7)
51 #define TYPE_SUG (1<<8)
52 #define TYPE_REC (1<<9)
53 #define TYPE_REQ (1<<10)
54 #define TYPE_PREREQ (1<<11)
56 #define TYPE_CYCLETAIL (1<<16)
57 #define TYPE_CYCLEHEAD (1<<17)
59 #define EDGEDATA_BLOCK 127
62 transaction_clone_orderdata(Transaction *trans, Transaction *srctrans)
64 struct s_TransactionOrderdata *od = srctrans->orderdata;
67 trans->orderdata = solv_calloc(1, sizeof(*trans->orderdata));
68 trans->orderdata->tes = solv_memdup2(od->tes, od->ntes, sizeof(*od->tes));
69 trans->orderdata->ntes = od->ntes;
70 trans->orderdata->invedgedata = solv_memdup2(od->invedgedata, od->ninvedgedata, sizeof(Id));
71 trans->orderdata->ninvedgedata = od->ninvedgedata;
74 trans->orderdata->cycles = solv_calloc(1, sizeof(Queue));
75 queue_init_clone(trans->orderdata->cycles, od->cycles);
79 trans->orderdata->edgedataq = solv_calloc(1, sizeof(Queue));
80 queue_init_clone(trans->orderdata->edgedataq, od->edgedataq);
85 transaction_free_orderdata(Transaction *trans)
89 struct s_TransactionOrderdata *od = trans->orderdata;
90 od->tes = solv_free(od->tes);
91 od->invedgedata = solv_free(od->invedgedata);
94 queue_free(od->cycles);
95 od->cycles = solv_free(od->cycles);
99 queue_init(od->edgedataq);
100 od->edgedataq = solv_free(od->edgedataq);
102 trans->orderdata = solv_free(trans->orderdata);
108 struct s_TransactionElement *tes;
121 addteedge(struct orderdata *od, int from, int to, int type)
124 struct s_TransactionElement *te;
129 /* 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); */
132 for (i = te->edges; od->edgedata[i]; i += 2)
133 if (od->edgedata[i] == to)
137 od->edgedata[i + 1] |= type;
140 if (i + 1 == od->nedgedata)
142 /* printf("tail add %d\n", i - te->edges); */
145 od->edgedata = solv_extend(od->edgedata, od->nedgedata, 3, sizeof(Id), EDGEDATA_BLOCK);
149 /* printf("extend %d\n", i - te->edges); */
150 od->edgedata = solv_extend(od->edgedata, od->nedgedata, 3 + (i - te->edges), sizeof(Id), EDGEDATA_BLOCK);
152 memcpy(od->edgedata + od->nedgedata, od->edgedata + te->edges, sizeof(Id) * (i - te->edges));
153 i = od->nedgedata + (i - te->edges);
154 te->edges = od->nedgedata;
156 od->edgedata[i] = to;
157 od->edgedata[i + 1] = type;
158 od->edgedata[i + 2] = 0; /* end marker */
159 od->nedgedata = i + 3;
163 addedge(struct orderdata *od, Id from, Id to, int type)
165 Transaction *trans = od->trans;
166 Pool *pool = trans->pool;
168 struct s_TransactionElement *te;
171 /* printf("addedge %d %d type %d\n", from, to, type); */
172 s = pool->solvables + from;
173 if (s->repo == pool->installed && trans->transaction_installed[from - pool->installed->start])
175 /* obsolete, map to install */
176 if (trans->transaction_installed[from - pool->installed->start] > 0)
177 from = trans->transaction_installed[from - pool->installed->start];
183 queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
184 transaction_all_obs_pkgs(trans, from, &ti);
185 for (i = 0; i < ti.count; i++)
186 addedge(od, ti.elements[i], to, type);
191 s = pool->solvables + to;
192 if (s->repo == pool->installed && trans->transaction_installed[to - pool->installed->start])
194 /* obsolete, map to install */
195 if (trans->transaction_installed[to - pool->installed->start] > 0)
196 to = trans->transaction_installed[to - pool->installed->start];
202 queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
203 transaction_all_obs_pkgs(trans, to, &ti);
204 for (i = 0; i < ti.count; i++)
205 addedge(od, from, ti.elements[i], type);
211 /* map from/to to te numbers */
212 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
219 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
226 addteedge(od, from, to, type);
230 havescripts(Pool *pool, Id solvid, Queue *ignoreinst)
232 Solvable *s = pool->solvables + solvid;
236 reqp = s->repo->idarraydata + s->requires;
237 while ((req = *reqp++) != 0)
238 if (req == SOLVABLE_PREREQMARKER)
242 while ((req = *reqp++) != 0)
244 const char *dep = pool_id2str(pool, req);
245 if (*dep == '/' && strcmp(dep, "/sbin/ldconfig") != 0)
247 if (ignoreinst && ignoreinst->count)
250 for (i = 0; i < ignoreinst->count; i++)
251 if (req == ignoreinst->elements[i])
253 if (i < ignoreinst->count)
264 addsolvableedges(struct orderdata *od, Solvable *s)
266 Transaction *trans = od->trans;
267 Pool *pool = trans->pool;
269 int i, j, pre, numins;
270 Repo *installed = pool->installed;
272 Queue depq, ignoreinst;
276 printf("addsolvableedges %s\n", pool_solvable2str(pool, s));
278 p = s - pool->solvables;
280 queue_init(&ignoreinst);
284 if (installed && s->repo == installed)
286 reqp = s->repo->idarraydata + s->requires;
287 while ((req = *reqp++) != 0)
288 if (req == SOLVABLE_PREREQMARKER)
290 solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &ignoreinst);
294 reqp = s->repo->idarraydata + s->requires;
296 while ((req = *reqp++) != 0)
298 if (req == SOLVABLE_PREREQMARKER)
303 if (pre == TYPE_PREREQ && ignoreinst.count)
305 /* check if this req is filtered. assumes that ignoreinst.count is small */
307 for (i = 0; i < ignoreinst.count; i++)
308 if (req == ignoreinst.elements[i])
310 if (i < ignoreinst.count)
314 numins = 0; /* number of packages to be installed providing it */
315 provbyinst = 0; /* provided by kept package */
316 FOR_PROVIDES(p2, pp2, req)
318 s2 = pool->solvables + p2;
321 depq.count = 0; /* self provides */
324 if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2))
329 if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2))
330 continue; /* package stays uninstalled */
332 if (s->repo == installed)
334 /* s gets uninstalled */
335 queue_pushunique(&depq, p2);
336 if (s2->repo != installed)
341 if (s2->repo == installed)
342 continue; /* s2 gets uninstalled */
343 queue_pushunique(&depq, p2);
346 if (provbyinst && s->repo == installed)
348 /* prune to harmless uninst->inst edges */
349 for (i = j = 0; i < depq.count; i++)
350 if (pool->solvables[depq.elements[i]].repo != installed)
351 depq.elements[j++] = depq.elements[i];
355 if (numins && depq.count)
357 if (s->repo == installed)
359 for (i = 0; i < depq.count; i++)
361 if (pool->solvables[depq.elements[i]].repo == installed)
363 for (j = 0; j < depq.count; j++)
365 if (pool->solvables[depq.elements[j]].repo != installed)
367 if (trans->transaction_installed[depq.elements[i] - pool->installed->start] == depq.elements[j])
368 continue; /* no self edge */
370 printf("add interrreq uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, depq.elements[i]), pool_dep2str(pool, req), pool_solvid2str(pool, depq.elements[j]));
372 addedge(od, depq.elements[i], depq.elements[j], pre == TYPE_PREREQ ? TYPE_PREREQ_UI : TYPE_REQ_UI);
378 /* no mixed types, remove all deps on uninstalls */
379 for (i = j = 0; i < depq.count; i++)
380 if (pool->solvables[depq.elements[i]].repo != installed)
381 depq.elements[j++] = depq.elements[i];
384 for (i = 0; i < depq.count; i++)
386 p2 = depq.elements[i];
387 if (pool->solvables[p2].repo != installed)
389 /* all elements of depq are installs, thus have different TEs */
390 if (s->repo != installed)
393 printf("add inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
395 addedge(od, p, p2, pre);
400 printf("add uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
402 addedge(od, p, p2, pre == TYPE_PREREQ ? TYPE_PREREQ_UI : TYPE_REQ_UI);
407 if (s->repo != installed)
408 continue; /* no inst->uninst edges, please! */
410 /* uninst -> uninst edge. Those make trouble. Only add if we must */
411 if (trans->transaction_installed[p - installed->start] && !havescripts(pool, p, &ignoreinst))
413 /* p is obsoleted by another package and has no scripts */
414 /* we assume that the obsoleter is good enough to replace p */
418 printf("add uninst->uninst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
420 addedge(od, p2, p, pre == TYPE_PREREQ ? TYPE_PREREQ_UU : TYPE_REQ_UU);
428 conp = s->repo->idarraydata + s->conflicts;
429 while ((con = *conp++) != 0)
431 FOR_PROVIDES(p2, pp2, con)
435 s2 = pool->solvables + p2;
438 if (s->repo == installed)
440 if (s2->repo != installed && MAPTST(&trans->transactsmap, p2))
442 /* deinstall p before installing p2 */
444 printf("add conflict uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p2), pool_dep2str(pool, con), pool_solvid2str(pool, p));
446 addedge(od, p2, p, TYPE_CON);
451 if (s2->repo == installed && MAPTST(&trans->transactsmap, p2))
453 /* deinstall p2 before installing p */
455 printf("add conflict uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, con), pool_solvid2str(pool, p2));
457 addedge(od, p, p2, TYPE_CON);
464 if (s->recommends && s->repo != installed)
467 recp = s->repo->idarraydata + s->recommends;
468 while ((rec = *recp++) != 0)
471 FOR_PROVIDES(p2, pp2, rec)
473 s2 = pool->solvables + p2;
476 depq.count = 0; /* self provides */
479 if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2))
481 if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2))
482 continue; /* package stays uninstalled */
483 if (s2->repo != installed)
484 queue_pushunique(&depq, p2);
486 for (i = 0; i < depq.count; i++)
488 p2 = depq.elements[i];
489 if (pool->solvables[p2].repo != installed)
492 printf("add recommends inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, rec), pool_solvid2str(pool, p2));
494 addedge(od, p, p2, TYPE_REC);
499 if (s->suggests && s->repo != installed)
502 sugp = s->repo->idarraydata + s->suggests;
503 while ((sug = *sugp++) != 0)
506 FOR_PROVIDES(p2, pp2, sug)
508 s2 = pool->solvables + p2;
511 depq.count = 0; /* self provides */
514 if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2))
516 if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2))
517 continue; /* package stays uninstalled */
518 if (s2->repo != installed)
519 queue_pushunique(&depq, p2);
521 for (i = 0; i < depq.count; i++)
523 p2 = depq.elements[i];
524 if (pool->solvables[p2].repo != installed)
527 printf("add suggests inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, sug), pool_solvid2str(pool, p2));
529 addedge(od, p, p2, TYPE_SUG);
534 if (s->repo == installed && solvable_lookup_idarray(s, SOLVABLE_TRIGGERS, &depq) && depq.count)
536 /* we're getting deinstalled/updated. Try to do this before our
537 * triggers are hit */
538 for (i = 0; i < depq.count; i++)
540 Id tri = depq.elements[i];
541 FOR_PROVIDES(p2, pp2, tri)
545 s2 = pool->solvables + p2;
548 if (s2->name == s->name)
549 continue; /* obsoleted anyway */
550 if (s2->repo != installed && MAPTST(&trans->transactsmap, p2))
552 /* deinstall/update p before installing p2 */
554 printf("add trigger uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p2), pool_dep2str(pool, tri), pool_solvid2str(pool, p));
556 addedge(od, p2, p, TYPE_CON);
561 queue_free(&ignoreinst);
566 scriptletedge(Pool *pool, struct orderdata *od, Id *cycle, int k)
568 int deg = od->edgedata[cycle[k + 1] + 1];
569 if ((deg & TYPE_REQ_UU) || (deg & TYPE_PREREQ_UU))
571 /* the UU edges are reverse edges, so we have to check the next element for scripts */
572 if (havescripts(pool, od->tes[cycle[k + 2]].p, 0))
574 deg &= ~(TYPE_REQ_UU | TYPE_PREREQ_UU);
576 if (deg && havescripts(pool, od->tes[cycle[k]].p, 0))
581 /* break an edge in a cycle */
583 breakcycle(struct orderdata *od, Id *cycle)
585 Pool *pool = od->trans->pool;
586 Id ddegmin, ddegmax, ddeg;
588 struct s_TransactionElement *te;
591 ddegmin = ddegmax = 0;
592 for (k = 0; cycle[k + 1]; k += 2)
594 ddeg = od->edgedata[cycle[k + 1] + 1];
595 /* map UU to UI for the comparison */
596 if (ddeg & TYPE_REQ_UU)
601 if (ddeg & TYPE_PREREQ_UU)
603 ddeg ^= TYPE_PREREQ_UU;
604 ddeg |= TYPE_PREREQ_UI;
608 if (!k || ddeg < ddegmin)
613 else if (ddeg == ddegmin)
615 if (scriptletedge(pool, od, cycle, l) && !scriptletedge(pool, od, cycle, k))
617 /* prefer k, as l comes from a package with contains scriptlets */
623 /* record brkoen cycle starting with the tail */
624 queue_push(&od->cycles, od->cyclesdata.count); /* offset into data */
625 queue_push(&od->cycles, k / 2); /* cycle elements */
626 queue_push(&od->cycles, od->edgedata[cycle[l + 1] + 1]); /* broken edge */
627 queue_push(&od->cycles, (ddegmax << 16) | ddegmin); /* max/min values */
634 queue_push(&od->cyclesdata, cycle[k]);
638 queue_push(&od->cyclesdata, 0); /* mark end */
640 /* break that edge */
641 od->edgedata[cycle[l + 1] + 1] |= TYPE_BROKEN;
644 IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
646 else if (ddegmin < TYPE_REQ)
649 /* cycle recorded, print it */
650 if (ddegmin >= TYPE_REQ && (ddegmax & TYPE_PREREQ) != 0)
651 POOL_DEBUG(SOLV_DEBUG_STATS, "CRITICAL ");
652 POOL_DEBUG(SOLV_DEBUG_STATS, "cycle: --> ");
653 for (k = 0; cycle[k + 1]; k += 2)
655 te = od->tes + cycle[k];
656 if ((od->edgedata[cycle[k + 1] + 1] & TYPE_BROKEN) != 0)
657 POOL_DEBUG(SOLV_DEBUG_STATS, "%s ##%x##> ", pool_solvid2str(pool, te->p), od->edgedata[cycle[k + 1] + 1]);
659 POOL_DEBUG(SOLV_DEBUG_STATS, "%s --%x--> ", pool_solvid2str(pool, te->p), od->edgedata[cycle[k + 1] + 1]);
661 POOL_DEBUG(SOLV_DEBUG_STATS, "\n");
666 dump_tes(struct orderdata *od)
668 Pool *pool = od->trans->pool;
671 struct s_TransactionElement *te, *te2;
674 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
676 Solvable *s = pool->solvables + te->p;
677 POOL_DEBUG(SOLV_DEBUG_RESULT, "TE %4d: %c%s\n", i, s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s));
678 if (s->repo != pool->installed)
681 transaction_all_obs_pkgs(od->trans, te->p, &obsq);
682 for (j = 0; j < obsq.count; j++)
683 POOL_DEBUG(SOLV_DEBUG_RESULT, " -%s\n", pool_solvid2str(pool, obsq.elements[j]));
685 for (j = te->edges; od->edgedata[j]; j += 2)
687 te2 = od->tes + od->edgedata[j];
688 if ((od->edgedata[j + 1] & TYPE_BROKEN) == 0)
689 POOL_DEBUG(SOLV_DEBUG_RESULT, " --%x--> TE %4d: %s\n", od->edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2->p));
691 POOL_DEBUG(SOLV_DEBUG_RESULT, " ##%x##> TE %4d: %s\n", od->edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2->p));
698 reachable(struct orderdata *od, Id i)
700 struct s_TransactionElement *te = od->tes + i;
706 for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
708 if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
710 if (!od->tes[k].mark)
712 if (od->tes[k].mark == 2)
722 addcycleedges(struct orderdata *od, Id *cycle, Queue *todo)
725 Transaction *trans = od->trans;
726 Pool *pool = trans->pool;
728 struct s_TransactionElement *te;
733 printf("addcycleedges\n");
734 for (i = 0; (j = cycle[i]) != 0; i++)
735 printf("cycle %s\n", pool_solvid2str(pool, od->tes[j].p));
738 /* first add all the tail cycle edges */
740 /* see what we can reach from the cycle */
742 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
744 for (i = 0; (j = cycle[i]) != 0; i++)
746 od->tes[j].mark = -1;
755 te->mark = te->mark < 0 ? 2 : 1;
756 for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
758 if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
760 if (od->tes[k].mark > 0)
761 continue; /* no need to visit again */
765 /* now all cycle TEs are marked with 2, all TEs reachable
766 * from the cycle are marked with 1 */
768 od->tes[tail].mark = 1; /* no need to add edges */
770 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
773 continue; /* reachable from cycle */
774 for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
776 if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
778 if (od->tes[k].mark != 2)
780 /* We found an edge to the cycle. Add an extra edge to the tail */
781 /* the TE was not reachable, so we're not creating a new cycle! */
783 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));
785 j -= te->edges; /* in case we move */
786 addteedge(od, i, tail, TYPE_CYCLETAIL);
788 break; /* one edge is enough */
792 /* now add all head cycle edges */
795 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
798 for (i = 0; (j = cycle[i]) != 0; i++)
803 /* first the head to save some time */
805 for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
807 if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
809 if (!od->tes[k].mark)
811 if (od->tes[k].mark == -1)
812 od->tes[k].mark = -2; /* no need for another edge */
814 for (i = 0; cycle[i] != 0; i++)
816 if (cycle[i] == head)
818 te = od->tes + cycle[i];
819 for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
821 if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
823 /* see if we can reach a cycle TE from k */
824 if (!od->tes[k].mark)
826 if (od->tes[k].mark == -1)
829 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));
831 addteedge(od, head, k, TYPE_CYCLEHEAD);
832 od->tes[k].mark = -2; /* no need to add that one again */
839 share_cycle(struct orderdata *od, Id p1, Id p2)
842 for (i = 0; i < od->cyclesdata.count; i++)
844 Id p = od->cyclesdata.elements[i];
847 else if ((p == p1 || p == p2) && ++seen == 2)
854 transaction_order(Transaction *trans, int flags)
856 Pool *pool = trans->pool;
857 Queue *tr = &trans->steps;
858 Repo *installed = pool->installed;
861 int i, j, k, numte, numedge;
863 struct s_TransactionElement *te;
864 Queue todo, obsq, samerepoq, uninstq;
870 int lastmedia, lastte;
872 unsigned char *incycle;
874 start = now = solv_timems(0);
875 POOL_DEBUG(SOLV_DEBUG_STATS, "ordering transaction\n");
876 /* free old data if present */
877 if (trans->orderdata)
878 transaction_free_orderdata(trans);
880 /* create a transaction element for every active component */
882 for (i = 0; i < tr->count; i++)
885 s = pool->solvables + p;
886 if (installed && s->repo == installed && trans->transaction_installed[p - installed->start])
890 POOL_DEBUG(SOLV_DEBUG_STATS, "transaction elements: %d\n", numte);
892 return; /* nothing to do... */
894 numte++; /* leave first one zero */
895 memset(&od, 0, sizeof(od));
898 od.tes = solv_calloc(numte, sizeof(*od.tes));
899 od.edgedata = solv_extend(0, 0, 1, sizeof(Id), EDGEDATA_BLOCK);
902 queue_init(&od.cycles);
903 queue_init(&od.cyclesdata);
904 queue_init(&od.edgedataq);
907 for (i = 0, te = od.tes + 1; i < tr->count; i++)
910 s = pool->solvables + p;
911 if (installed && s->repo == installed && trans->transaction_installed[p - installed->start])
917 /* create dependency graph */
918 for (i = 0; i < tr->count; i++)
919 addsolvableedges(&od, pool->solvables + tr->elements[i]);
923 for (i = 1, te = od.tes + i; i < numte; i++, te++)
924 for (j = te->edges; od.edgedata[j]; j += 2)
926 POOL_DEBUG(SOLV_DEBUG_STATS, "edges: %d, edge space: %d\n", numedge, od.nedgedata / 2);
927 POOL_DEBUG(SOLV_DEBUG_STATS, "edge creation took %d ms\n", solv_timems(now));
933 now = solv_timems(0);
934 /* kill all cycles */
936 for (i = numte - 1; i > 0; i--)
937 queue_push(&todo, i);
941 i = queue_pop(&todo);
942 /* printf("- look at TE %d\n", i); */
946 od.tes[i].mark = 2; /* done with that one */
951 continue; /* already finished before */
954 int edgestovisit = 0;
955 /* new node, visit edges */
956 for (j = te->edges; (k = od.edgedata[j]) != 0; j += 2)
958 if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
960 if (od.tes[k].mark == 2)
961 continue; /* no need to visit again */
963 queue_push(&todo, -i); /* end of edges marker */
964 queue_push(&todo, k);
967 te->mark = 2; /* no edges, done with that one */
969 te->mark = 1; /* under investigation */
972 /* oh no, we found a cycle */
973 /* find start of cycle node (<0) */
974 for (j = todo.count - 1; j >= 0; j--)
975 if (todo.elements[j] == -i)
979 /* build te/edge chain */
981 for (j = k; j < todo.count; j++)
982 if (todo.elements[j] < 0)
983 todo.elements[k++] = -todo.elements[j];
984 cycel = k - cycstart;
986 /* make room for edges, two extra element for cycle loop + terminating 0 */
987 while (todo.count < cycstart + 2 * cycel + 2)
988 queue_push(&todo, 0);
989 cycle = todo.elements + cycstart;
990 cycle[cycel] = i; /* close the loop */
991 cycle[2 * cycel + 1] = 0; /* terminator */
992 for (k = cycel; k > 0; k--)
994 cycle[k * 2] = cycle[k];
995 te = od.tes + cycle[k - 1];
996 assert(te->mark == 1);
997 te->mark = 0; /* reset investigation marker */
998 /* printf("searching for edge from %d to %d\n", cycle[k - 1], cycle[k]); */
999 for (j = te->edges; od.edgedata[j]; j += 2)
1000 if (od.edgedata[j] == cycle[k])
1002 assert(od.edgedata[j]);
1003 cycle[k * 2 - 1] = j;
1005 /* now cycle looks like this: */
1006 /* te1 edge te2 edge te3 ... teN edge te1 0 */
1007 breakcycle(&od, cycle);
1008 /* restart with start of cycle */
1009 todo.count = cycstart + 1;
1011 POOL_DEBUG(SOLV_DEBUG_STATS, "cycles broken: %d\n", od.ncycles);
1012 POOL_DEBUG(SOLV_DEBUG_STATS, "cycle breaking took %d ms\n", solv_timems(now));
1015 if (od.cycles.count)
1017 now = solv_timems(0);
1018 incycle = solv_calloc(numte, 1);
1019 /* now go through all broken cycles and create cycle edges to help
1021 for (i = od.cycles.count - 4; i >= 0; i -= 4)
1023 if (od.cycles.elements[i + 2] >= TYPE_REQ)
1024 addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
1026 for (i = od.cycles.count - 4; i >= 0; i -= 4)
1028 if (od.cycles.elements[i + 2] < TYPE_REQ)
1029 addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
1031 for (i = od.cycles.count - 4; i >= 0; i -= 4)
1033 for (j = od.cycles.elements[i]; od.cyclesdata.elements[j]; j++)
1034 incycle[od.cyclesdata.elements[j]] = 1;
1036 POOL_DEBUG(SOLV_DEBUG_STATS, "cycle edge creation took %d ms\n", solv_timems(now));
1042 if ((flags & SOLVER_TRANSACTION_KEEP_ORDEREDGES) != 0)
1044 queue_insertn(&od.edgedataq, 0, od.nedgedata, od.edgedata);
1045 queue_insertn(&od.edgedataq, 0, numte, 0);
1046 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1047 od.edgedataq.elements[i] = te->edges + numte;
1050 /* all edges are finally set up and there are no cycles, now the easy part.
1051 * Create an ordered transaction */
1052 now = solv_timems(0);
1053 /* first invert all edges */
1054 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1055 te->mark = 1; /* term 0 */
1056 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1058 for (j = te->edges; od.edgedata[j]; j += 2)
1060 if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
1062 od.tes[od.edgedata[j]].mark++;
1066 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1071 POOL_DEBUG(SOLV_DEBUG_STATS, "invedge space: %d\n", j + 1);
1072 od.invedgedata = solv_calloc(j + 1, sizeof(Id));
1073 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1075 for (j = te->edges; od.edgedata[j]; j += 2)
1077 if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
1079 od.invedgedata[--od.tes[od.edgedata[j]].mark] = i;
1082 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1083 te->edges = te->mark; /* edges now points into invedgedata */
1084 od.edgedata = solv_free(od.edgedata);
1085 od.nedgedata = j + 1;
1087 /* now the final ordering */
1088 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1090 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1091 for (j = te->edges; od.invedgedata[j]; j++)
1092 od.tes[od.invedgedata[j]].mark++;
1094 queue_init(&samerepoq);
1095 queue_init(&uninstq);
1097 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1100 if (installed && pool->solvables[te->p].repo == installed)
1101 queue_push(&uninstq, i);
1103 queue_push(&todo, i);
1105 assert(todo.count > 0 || uninstq.count > 0);
1106 oldcount = tr->count;
1114 temedianr = solv_calloc(numte, sizeof(Id));
1115 for (i = 1; i < numte; i++)
1117 Solvable *s = pool->solvables + od.tes[i].p;
1118 if (installed && s->repo == installed)
1121 j = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
1126 /* select an TE i */
1128 i = queue_shift(&uninstq);
1129 else if (samerepoq.count)
1131 if (lastte && incycle && incycle[lastte])
1133 /* last installed package was in a cycle, prefer packages from the same cycle */
1134 for (j = 0; j < samerepoq.count; j++)
1135 if (incycle[samerepoq.elements[j]] && share_cycle(&od, lastte, samerepoq.elements[j]))
1137 /* yes, bring to front! */
1138 i = samerepoq.elements[j];
1139 queue_delete(&samerepoq, j);
1140 queue_unshift(&samerepoq, i);
1144 i = queue_shift(&samerepoq);
1146 else if (todo.count)
1148 /* find next repo/media */
1149 for (j = 0; j < todo.count; j++)
1151 if (!j || temedianr[todo.elements[j]] < lastmedia)
1154 lastmedia = temedianr[todo.elements[j]];
1157 lastrepo = pool->solvables[od.tes[todo.elements[i]].p].repo;
1159 /* move all matching TEs to samerepoq */
1160 for (i = j = 0; j < todo.count; j++)
1162 int k = todo.elements[j];
1163 if (temedianr[k] == lastmedia && pool->solvables[od.tes[k].p].repo == lastrepo)
1164 queue_push(&samerepoq, k);
1166 todo.elements[i++] = k;
1170 assert(samerepoq.count);
1171 i = queue_shift(&samerepoq);
1177 queue_push(tr, te->p);
1178 if (pool->solvables[te->p].repo != installed)
1182 printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]);
1184 for (j = te->edges; od.invedgedata[j]; j++)
1186 struct s_TransactionElement *te2 = od.tes + od.invedgedata[j];
1187 assert(te2->mark > 0);
1188 if (--te2->mark == 0)
1190 Solvable *s = pool->solvables + te2->p;
1192 printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata[j]]);
1194 if (installed && s->repo == installed)
1195 queue_push(&uninstq, od.invedgedata[j]);
1196 else if (s->repo == lastrepo && temedianr[od.invedgedata[j]] == lastmedia)
1197 queue_push(&samerepoq, od.invedgedata[j]);
1199 queue_push(&todo, od.invedgedata[j]);
1203 solv_free(temedianr);
1206 queue_free(&samerepoq);
1207 queue_free(&uninstq);
1209 for (i = 1, te = od.tes + i; i < numte; i++, te++)
1210 assert(te->mark == 0);
1212 /* add back obsoleted packages */
1213 transaction_add_obsoleted(trans);
1214 assert(tr->count == oldcount);
1216 POOL_DEBUG(SOLV_DEBUG_STATS, "creating new transaction took %d ms\n", solv_timems(now));
1217 POOL_DEBUG(SOLV_DEBUG_STATS, "transaction ordering took %d ms\n", solv_timems(start));
1219 if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDERCYCLES | SOLVER_TRANSACTION_KEEP_ORDEREDGES)) != 0)
1221 struct s_TransactionOrderdata *tod;
1222 trans->orderdata = tod = solv_calloc(1, sizeof(*trans->orderdata));
1223 if ((flags & SOLVER_TRANSACTION_KEEP_ORDERCYCLES) != 0)
1225 Queue *cycles = tod->cycles = solv_calloc(1, sizeof(Queue));
1226 queue_init_clone(cycles, &od.cyclesdata);
1227 /* map from tes to packages */
1228 for (i = 0; i < cycles->count; i++)
1229 if (cycles->elements[i])
1230 cycles->elements[i] = od.tes[cycles->elements[i]].p;
1231 queue_insertn(cycles, cycles->count, od.cycles.count, od.cycles.elements);
1232 queue_push(cycles, od.cycles.count / 4);
1234 if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDEREDGES)) != 0)
1238 tod->invedgedata = od.invedgedata;
1239 tod->ninvedgedata = od.nedgedata;
1243 if ((flags & SOLVER_TRANSACTION_KEEP_ORDEREDGES) != 0)
1245 Queue *edgedataq = tod->edgedataq = solv_calloc(1, sizeof(Queue));
1246 queue_init_clone(edgedataq, &od.edgedataq);
1250 solv_free(od.invedgedata);
1251 queue_free(&od.cycles);
1252 queue_free(&od.edgedataq);
1253 queue_free(&od.cyclesdata);
1258 transaction_order_add_choices(Transaction *trans, Id chosen, Queue *choices)
1261 struct s_TransactionOrderdata *od = trans->orderdata;
1262 struct s_TransactionElement *te;
1265 return choices->count;
1268 /* initialization step */
1269 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
1271 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
1273 for (j = te->edges; od->invedgedata[j]; j++)
1274 od->tes[od->invedgedata[j]].mark++;
1276 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
1278 queue_push(choices, te->p);
1279 return choices->count;
1281 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
1282 if (te->p == chosen)
1285 return choices->count;
1288 /* hey! out-of-order installation! */
1291 for (j = te->edges; od->invedgedata[j]; j++)
1293 te = od->tes + od->invedgedata[j];
1294 assert(te->mark > 0 || te->mark == -1);
1295 if (te->mark > 0 && --te->mark == 0)
1296 queue_push(choices, te->p);
1298 return choices->count;
1302 transaction_add_obsoleted(Transaction *trans)
1304 Pool *pool = trans->pool;
1305 Repo *installed = pool->installed;
1312 if (!installed || !trans->steps.count)
1314 /* calculate upper bound */
1316 FOR_REPO_SOLVABLES(installed, p, s)
1317 if (MAPTST(&trans->transactsmap, p))
1322 steps = &trans->steps;
1323 queue_insertn(steps, 0, max, 0);
1326 map_init(&done, installed->end - installed->start);
1328 for (j = 0, i = max; i < steps->count; i++)
1330 p = trans->steps.elements[i];
1331 if (pool->solvables[p].repo == installed)
1333 if (!trans->transaction_installed[p - pool->installed->start])
1334 trans->steps.elements[j++] = p;
1337 trans->steps.elements[j++] = p;
1339 transaction_all_obs_pkgs(trans, p, &obsq);
1340 for (k = 0; k < obsq.count; k++)
1342 p = obsq.elements[k];
1343 assert(p >= installed->start && p < installed->end);
1344 if (!MAPTST(&trans->transactsmap, p)) /* just in case */
1346 if (MAPTST(&done, p - installed->start))
1348 MAPSET(&done, p - installed->start);
1349 trans->steps.elements[j++] = p;
1353 /* free unneeded space */
1354 queue_truncate(steps, j);
1360 transaction_check_pkg(Transaction *trans, Id tepkg, Id pkg, Map *ins, Map *seen, int onlyprereq, Id noconfpkg, int depth)
1362 Pool *pool = trans->pool;
1367 if (MAPTST(seen, pkg))
1370 s = pool->solvables + pkg;
1372 printf("- %*s%c%s\n", depth * 2, "", s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s));
1378 reqp = s->repo->idarraydata + s->requires;
1379 while ((req = *reqp++) != 0)
1381 if (req == SOLVABLE_PREREQMARKER)
1386 if (onlyprereq && !inpre)
1388 if (!strncmp(pool_id2str(pool, req), "rpmlib(", 7))
1391 /* first check kept packages, then freshly installed, then not yet uninstalled */
1392 FOR_PROVIDES(p, pp, req)
1394 if (!MAPTST(ins, p))
1396 if (MAPTST(&trans->transactsmap, p))
1399 transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
1403 FOR_PROVIDES(p, pp, req)
1405 if (!MAPTST(ins, p))
1407 if (pool->solvables[p].repo == pool->installed)
1410 transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
1415 FOR_PROVIDES(p, pp, req)
1417 if (!MAPTST(ins, p))
1420 transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
1425 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));
1432 transaction_check_order(Transaction *trans)
1434 Pool *pool = trans->pool;
1440 POOL_DEBUG(SOLV_DEBUG_RESULT, "\nchecking transaction order...\n");
1441 map_init(&ins, pool->nsolvables);
1442 map_init(&seen, pool->nsolvables);
1443 if (pool->installed)
1445 FOR_REPO_SOLVABLES(pool->installed, p, s)
1449 for (i = 0; i < trans->steps.count; i++)
1451 p = trans->steps.elements[i];
1452 s = pool->solvables + p;
1453 if (s->repo != pool->installed)
1455 if (s->repo != pool->installed)
1457 if (havescripts(pool, p, 0))
1460 transaction_check_pkg(trans, p, p, &ins, &seen, 1, lastins, 0);
1462 if (s->repo == pool->installed)
1467 POOL_DEBUG(SOLV_DEBUG_RESULT, "transaction order check done.\n");
1471 transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity)
1473 struct s_TransactionOrderdata *od = trans->orderdata;
1475 int i, cid, ncycles;
1478 if (!od || !od->cycles || !od->cycles->count)
1481 ncycles = cq->elements[cq->count - 1];
1482 i = cq->count - 1 - ncycles * 4;
1483 for (cid = 1; cid <= ncycles; cid++, i += 4)
1487 int cmin = cq->elements[i + 3] & 0xffff;
1488 int cmax = (cq->elements[i + 3] >> 16) & 0xffff;
1489 if (minseverity >= SOLVER_ORDERCYCLE_NORMAL && cmin < TYPE_REQ)
1491 if (minseverity >= SOLVER_ORDERCYCLE_CRITICAL && (cmax & TYPE_PREREQ) == 0)
1499 transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q)
1501 struct s_TransactionOrderdata *od = trans->orderdata;
1503 int cmin, cmax, severity;
1507 if (!od || !od->cycles || !od->cycles->count)
1508 return SOLVER_ORDERCYCLE_HARMLESS;
1510 ncycles = cq->elements[cq->count - 1];
1511 if (cid < 1 || cid > ncycles)
1512 return SOLVER_ORDERCYCLE_HARMLESS;
1513 cid = cq->count - 1 - 4 * (ncycles - cid + 1);
1514 cmin = cq->elements[cid + 3] & 0xffff;
1515 cmax = (cq->elements[cid + 3] >> 16) & 0xffff;
1516 if (cmin < TYPE_REQ)
1517 severity = SOLVER_ORDERCYCLE_HARMLESS;
1518 else if ((cmax & TYPE_PREREQ) == 0)
1519 severity = SOLVER_ORDERCYCLE_NORMAL;
1521 severity = SOLVER_ORDERCYCLE_CRITICAL;
1523 queue_insertn(q, 0, cq->elements[cid + 1], cq->elements + cq->elements[cid]);
1528 transaction_order_get_edges(Transaction *trans, Id p, Queue *q, int unbroken)
1530 struct s_TransactionOrderdata *od = trans->orderdata;
1531 struct s_TransactionElement *te;
1536 if (!od || !od->edgedataq)
1538 for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
1544 for (i = eq->elements[i]; eq->elements[i]; i += 2)
1546 int type = eq->elements[i + 1];
1549 type &= ~(TYPE_BROKEN | TYPE_CYCLETAIL | TYPE_CYCLEHEAD);
1553 queue_push2(q, od->tes[eq->elements[i]].p, type);