Imported Upstream version 0.6.9
[platform/upstream/libsolv.git] / src / solver.c
1 /*
2  * Copyright (c) 2007-2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * solver.c
10  *
11  * SAT based dependency solver
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 "solver.h"
21 #include "solver_private.h"
22 #include "bitmap.h"
23 #include "pool.h"
24 #include "util.h"
25 #include "policy.h"
26 #include "poolarch.h"
27 #include "solverdebug.h"
28 #include "cplxdeps.h"
29 #include "linkedpkg.h"
30
31 #define RULES_BLOCK 63
32
33 /********************************************************************
34  *
35  * dependency check helpers
36  *
37  */
38
39 /*-------------------------------------------------------------------
40  * handle split provides
41  *
42  * a splitprovides dep looks like
43  *     namespace:splitprovides(pkg REL_WITH path)
44  * and is only true if pkg is installed and contains the specified path.
45  * we also make sure that pkg is selected for an update, otherwise the
46  * update would always be forced onto the user.
47  * Map m is the map used when called from dep_possible.
48  */
49
50 static int
51 solver_is_updating(Solver *solv, Id p)
52 {
53   /* check if the update rule is true */
54   Pool *pool = solv->pool;
55   Rule *r;
56   Id l, pp;
57   if (solv->decisionmap[p] >= 0)
58     return 0;   /* old package stayed */
59   r = solv->rules + solv->updaterules + (p - solv->installed->start);
60   FOR_RULELITERALS(l, pp, r)
61     if (l > 0 && l != p && solv->decisionmap[l] > 0)
62       return 1;
63   return 0;
64 }
65
66 int
67 solver_splitprovides(Solver *solv, Id dep, Map *m)
68 {
69   Pool *pool = solv->pool;
70   Id p, pp;
71   Reldep *rd;
72   Solvable *s;
73
74   if (!solv->dosplitprovides || !solv->installed)
75     return 0;
76   if (!ISRELDEP(dep))
77     return 0;
78   rd = GETRELDEP(pool, dep);
79   if (rd->flags != REL_WITH)
80     return 0;
81   /*
82    * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
83    * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
84    * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
85    * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
86    * we filter the package name further down anyway).
87    */
88   if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
89     pp = pool_searchlazywhatprovidesq(pool, rd->evr);
90   else
91     pp = pool_whatprovides(pool, dep);
92   while ((p = pool->whatprovidesdata[pp++]) != 0)
93     {
94       /* here we have packages that provide the correct name and contain the path,
95        * now do extra filtering */
96       s = pool->solvables + p;
97       if (s->repo != solv->installed || s->name != rd->name)
98         continue;
99       /* check if the package is updated. if m is set, we're called from dep_possible */
100       if (m || solver_is_updating(solv, p))
101         return 1;
102     }
103   return 0;
104 }
105
106
107 /*-------------------------------------------------------------------
108  * solver_dep_installed
109  */
110
111 int
112 solver_dep_installed(Solver *solv, Id dep)
113 {
114 #if 0
115   Pool *pool = solv->pool;
116   Id p, pp;
117
118   if (ISRELDEP(dep))
119     {
120       Reldep *rd = GETRELDEP(pool, dep);
121       if (rd->flags == REL_AND)
122         {
123           if (!solver_dep_installed(solv, rd->name))
124             return 0;
125           return solver_dep_installed(solv, rd->evr);
126         }
127       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
128         return solver_dep_installed(solv, rd->evr);
129     }
130   FOR_PROVIDES(p, pp, dep)
131     {
132       if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
133         return 1;
134     }
135 #endif
136   return 0;
137 }
138
139 /* mirrors solver_dep_installed, but returns 2 if a
140  * dependency listed in solv->installsuppdepq was involved */
141 static int
142 solver_check_installsuppdepq_dep(Solver *solv, Id dep)
143 {
144   Pool *pool = solv->pool;
145   Id p, pp;
146   Queue *q;
147
148   if (ISRELDEP(dep))
149     {
150       Reldep *rd = GETRELDEP(pool, dep);
151       if (rd->flags == REL_AND)
152         {
153           int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
154           if (!r1)
155             return 0;
156           r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
157           if (!r2)
158             return 0;
159           return r1 == 2 || r2 == 2 ? 2 : 1;
160         }
161       if (rd->flags == REL_OR)
162         {
163           int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
164           r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
165           if (!r1 && !r2)
166             return 0;
167           return r1 == 2 || r2 == 2 ? 2 : 1;
168         }
169       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
170         return solver_splitprovides(solv, rd->evr, 0);
171       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
172         return solver_dep_installed(solv, rd->evr);
173       if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0)
174         {
175           int i;
176           for (i = 0; i < q->count; i++)
177             if (q->elements[i] == dep || q->elements[i] == rd->name)
178               return 2;
179         }
180     }
181   FOR_PROVIDES(p, pp, dep)
182     if (solv->decisionmap[p] > 0)
183       return 1;
184   return 0;
185 }
186
187 static int
188 solver_check_installsuppdepq(Solver *solv, Solvable *s)
189 {
190   Id sup, *supp;
191   supp = s->repo->idarraydata + s->supplements;
192   while ((sup = *supp++) != 0)
193     if (solver_check_installsuppdepq_dep(solv, sup) == 2)
194       return 1;
195   return 0;
196 }
197
198 static Id
199 autouninstall(Solver *solv, Id *problem)
200 {
201   Pool *pool = solv->pool;
202   int i;
203   int lastfeature = 0, lastupdate = 0;
204   Id v;
205   Id extraflags = -1;
206
207   for (i = 0; (v = problem[i]) != 0; i++)
208     {
209       if (v < 0)
210         extraflags &= solv->job.elements[-v - 1];
211       if (v >= solv->featurerules && v < solv->featurerules_end)
212         if (v > lastfeature)
213           lastfeature = v;
214       if (v >= solv->updaterules && v < solv->updaterules_end)
215         {
216           /* check if identical to feature rule */
217           Id p = solv->rules[v].p;
218           Rule *r;
219           if (p <= 0)
220             continue;
221           r = solv->rules + solv->featurerules + (p - solv->installed->start);
222           if (!r->p)
223             {
224               /* update rule == feature rule */
225               if (v > lastfeature)
226                 lastfeature = v;
227               continue;
228             }
229           if (v > lastupdate)
230             lastupdate = v;
231         }
232     }
233   if (!lastupdate && !lastfeature)
234     return 0;
235   v = lastupdate ? lastupdate : lastfeature;
236   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
237   solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
238   solver_disableproblem(solv, v);
239   if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
240     {
241       /* add the package to the updatepkgs list, this will automatically turn
242        * on cleandeps mode */
243       Id p = solv->rules[v].p;
244       if (!solv->cleandeps_updatepkgs)
245         {
246           solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
247           queue_init(solv->cleandeps_updatepkgs);
248         }
249       if (p > 0)
250         {
251           int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
252           queue_pushunique(solv->cleandeps_updatepkgs, p);
253           if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
254             solver_disablepolicyrules(solv);
255         }
256     }
257   return v;
258 }
259
260 /************************************************************************/
261
262 /*
263  * enable/disable learnt rules
264  *
265  * we have enabled or disabled some of our rules. We now reenable all
266  * of our learnt rules except the ones that were learnt from rules that
267  * are now disabled.
268  */
269 static void
270 enabledisablelearntrules(Solver *solv)
271 {
272   Pool *pool = solv->pool;
273   Rule *r;
274   Id why, *whyp;
275   int i;
276
277   POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
278   for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
279     {
280       whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
281       while ((why = *whyp++) != 0)
282         {
283           assert(why > 0 && why < i);
284           if (solv->rules[why].d < 0)
285             break;
286         }
287       /* why != 0: we found a disabled rule, disable the learnt rule */
288       if (why && r->d >= 0)
289         {
290           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
291             {
292               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "disabling ");
293               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
294             }
295           solver_disablerule(solv, r);
296         }
297       else if (!why && r->d < 0)
298         {
299           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
300             {
301               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "re-enabling ");
302               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
303             }
304           solver_enablerule(solv, r);
305         }
306     }
307 }
308
309
310 /*
311  * make assertion rules into decisions
312  *
313  * Go through rules and add direct assertions to the decisionqueue.
314  * If we find a conflict, disable rules and add them to problem queue.
315  */
316
317 static void
318 makeruledecisions(Solver *solv)
319 {
320   Pool *pool = solv->pool;
321   int i, ri, ii;
322   Rule *r, *rr;
323   Id v, vv;
324   int decisionstart;
325   int record_proof = 1;
326   int oldproblemcount;
327   int havedisabled = 0;
328
329   /* The system solvable is always installed first */
330   assert(solv->decisionq.count == 0);
331   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
332   queue_push(&solv->decisionq_why, 0);
333   solv->decisionmap[SYSTEMSOLVABLE] = 1;        /* installed at level '1' */
334
335   decisionstart = solv->decisionq.count;
336   for (;;)
337     {
338       /* if we needed to re-run, back up decisions to decisionstart */
339       while (solv->decisionq.count > decisionstart)
340         {
341           v = solv->decisionq.elements[--solv->decisionq.count];
342           --solv->decisionq_why.count;
343           vv = v > 0 ? v : -v;
344           solv->decisionmap[vv] = 0;
345         }
346
347       /* note that the ruleassertions queue is ordered */
348       for (ii = 0; ii < solv->ruleassertions.count; ii++)
349         {
350           ri = solv->ruleassertions.elements[ii];
351           r = solv->rules + ri;
352
353           if (havedisabled && ri >= solv->learntrules)
354             {
355               /* just started with learnt rule assertions. If we have disabled
356                * some rules, adapt the learnt rule status */
357               enabledisablelearntrules(solv);
358               havedisabled = 0;
359             }
360
361           if (r->d < 0 || !r->p || r->w2)       /* disabled, dummy or no assertion */
362             continue;
363
364           /* do weak rules in phase 2 */
365           if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri))
366             continue;
367
368           v = r->p;
369           vv = v > 0 ? v : -v;
370
371           if (!solv->decisionmap[vv])          /* if not yet decided */
372             {
373               queue_push(&solv->decisionq, v);
374               queue_push(&solv->decisionq_why, r - solv->rules);
375               solv->decisionmap[vv] = v > 0 ? 1 : -1;
376               IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
377                 {
378                   Solvable *s = solv->pool->solvables + vv;
379                   if (v < 0)
380                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
381                   else
382                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(solv->pool, s));
383                 }
384               continue;
385             }
386
387           /* check against previous decision: is there a conflict? */
388           if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
389             continue;
390           if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
391             continue;
392
393           /*
394            * found a conflict!
395            *
396            * The rule (r) we're currently processing says something
397            * different (v = r->p) than a previous decision (decisionmap[abs(v)])
398            * on this literal
399            */
400
401           if (ri >= solv->learntrules)
402             {
403               /* conflict with a learnt rule */
404               /* can happen when packages cannot be installed for multiple reasons. */
405               /* we disable the learnt rule in this case */
406               /* (XXX: we should really call analyze_unsolvable_rule here!) */
407               solver_disablerule(solv, r);
408               continue;
409             }
410
411           /*
412            * find the decision which is the "opposite" of the rule
413            */
414           for (i = 0; i < solv->decisionq.count; i++)
415             if (solv->decisionq.elements[i] == -v)
416               break;
417           assert(i < solv->decisionq.count);         /* assert that we found it */
418           oldproblemcount = solv->problems.count;
419
420           /*
421            * conflict with system solvable ?
422            */
423           if (v == -SYSTEMSOLVABLE)
424             {
425               if (record_proof)
426                 {
427                   queue_push(&solv->problems, solv->learnt_pool.count);
428                   queue_push(&solv->learnt_pool, ri);
429                   queue_push(&solv->learnt_pool, 0);
430                 }
431               else
432                 queue_push(&solv->problems, 0);
433               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
434               if  (ri >= solv->jobrules && ri < solv->jobrules_end)
435                 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
436               else
437                 v = ri;
438               queue_push(&solv->problems, v);
439               queue_push(&solv->problems, 0);
440               if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
441                 solv->problems.count = oldproblemcount;
442               solver_disableproblem(solv, v);
443               havedisabled = 1;
444               break;    /* start over */
445             }
446
447           assert(solv->decisionq_why.elements[i] > 0);
448
449           /*
450            * conflict with a pkg rule ?
451            */
452           if (solv->decisionq_why.elements[i] < solv->pkgrules_end)
453             {
454               if (record_proof)
455                 {
456                   queue_push(&solv->problems, solv->learnt_pool.count);
457                   queue_push(&solv->learnt_pool, ri);
458                   queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
459                   queue_push(&solv->learnt_pool, 0);
460                 }
461               else
462                 queue_push(&solv->problems, 0);
463               assert(v > 0 || v == -SYSTEMSOLVABLE);
464               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri);
465               if (ri >= solv->jobrules && ri < solv->jobrules_end)
466                 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
467               else
468                 v = ri;
469               queue_push(&solv->problems, v);
470               queue_push(&solv->problems, 0);
471               if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
472                 solv->problems.count = oldproblemcount;
473               solver_disableproblem(solv, v);
474               havedisabled = 1;
475               break;    /* start over */
476             }
477
478           /*
479            * conflict with another job or update/feature rule
480            */
481
482           /* record proof */
483           if (record_proof)
484             {
485               queue_push(&solv->problems, solv->learnt_pool.count);
486               queue_push(&solv->learnt_pool, ri);
487               queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
488               queue_push(&solv->learnt_pool, 0);
489             }
490           else
491             queue_push(&solv->problems, 0);
492
493           POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
494
495           /*
496            * push all of our rules (can only be feature or job rules)
497            * asserting this literal on the problem stack
498            */
499           for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
500             {
501               if (rr->d < 0                          /* disabled */
502                   || rr->w2)                         /*  or no assertion */
503                 continue;
504               if (rr->p != vv                        /* not affecting the literal */
505                   && rr->p != -vv)
506                 continue;
507               if (MAPTST(&solv->weakrulemap, i))     /* weak: silently ignore */
508                 continue;
509                 
510               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
511               solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
512                 
513               v = i;
514               if (i >= solv->jobrules && i < solv->jobrules_end)
515                 v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
516               queue_push(&solv->problems, v);
517             }
518           queue_push(&solv->problems, 0);
519
520           if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
521             solv->problems.count = oldproblemcount;
522
523           for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
524             solver_disableproblem(solv, solv->problems.elements[i]);
525           havedisabled = 1;
526           break;        /* start over */
527         }
528       if (ii < solv->ruleassertions.count)
529         continue;
530
531       /*
532        * phase 2: now do the weak assertions
533        */
534       for (ii = 0; ii < solv->ruleassertions.count; ii++)
535         {
536           ri = solv->ruleassertions.elements[ii];
537           r = solv->rules + ri;
538           if (r->d < 0 || r->w2)                         /* disabled or no assertion */
539             continue;
540           if (ri >= solv->learntrules || !MAPTST(&solv->weakrulemap, ri))       /* skip non-weak */
541             continue;
542           v = r->p;
543           vv = v > 0 ? v : -v;
544
545           if (!solv->decisionmap[vv])          /* if not yet decided */
546             {
547               queue_push(&solv->decisionq, v);
548               queue_push(&solv->decisionq_why, r - solv->rules);
549               solv->decisionmap[vv] = v > 0 ? 1 : -1;
550               IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
551                 {
552                   Solvable *s = solv->pool->solvables + vv;
553                   if (v < 0)
554                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
555                   else
556                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
557                 }
558               continue;
559             }
560           /* check against previous decision: is there a conflict? */
561           if (v > 0 && solv->decisionmap[vv] > 0)
562             continue;
563           if (v < 0 && solv->decisionmap[vv] < 0)
564             continue;
565
566           POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
567           solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r);
568
569           if (ri >= solv->jobrules && ri < solv->jobrules_end)
570             v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
571           else
572             v = ri;
573           solver_disableproblem(solv, v);
574           if (v < 0)
575             solver_reenablepolicyrules(solv, -v);
576           havedisabled = 1;
577           break;        /* start over */
578         }
579       if (ii == solv->ruleassertions.count)
580         break;  /* finished! */
581     }
582 }
583
584
585 /********************************************************************/
586 /* watches */
587
588
589 /*-------------------------------------------------------------------
590  * makewatches
591  *
592  * initial setup for all watches
593  */
594
595 static void
596 makewatches(Solver *solv)
597 {
598   Rule *r;
599   int i;
600   int nsolvables = solv->pool->nsolvables;
601
602   solv_free(solv->watches);
603                                        /* lower half for removals, upper half for installs */
604   solv->watches = solv_calloc(2 * nsolvables, sizeof(Id));
605 #if 1
606   /* do it reverse so pkg rules get triggered first (XXX: obsolete?) */
607   for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
608 #else
609   for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
610 #endif
611     {
612       if (!r->w2)               /* assertions do not need watches */
613         continue;
614
615       /* see addwatches_rule(solv, r) */
616       r->n1 = solv->watches[nsolvables + r->w1];
617       solv->watches[nsolvables + r->w1] = r - solv->rules;
618
619       r->n2 = solv->watches[nsolvables + r->w2];
620       solv->watches[nsolvables + r->w2] = r - solv->rules;
621     }
622 }
623
624
625 /*-------------------------------------------------------------------
626  *
627  * add watches (for a new learned rule)
628  * sets up watches for a single rule
629  *
630  * see also makewatches() above.
631  */
632
633 static inline void
634 addwatches_rule(Solver *solv, Rule *r)
635 {
636   int nsolvables = solv->pool->nsolvables;
637
638   r->n1 = solv->watches[nsolvables + r->w1];
639   solv->watches[nsolvables + r->w1] = r - solv->rules;
640
641   r->n2 = solv->watches[nsolvables + r->w2];
642   solv->watches[nsolvables + r->w2] = r - solv->rules;
643 }
644
645
646 /********************************************************************/
647 /*
648  * rule propagation
649  */
650
651
652 /* shortcuts to check if a literal (positive or negative) assignment
653  * evaluates to 'true' or 'false'
654  */
655 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
656 #define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
657 #define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0)
658
659 /*-------------------------------------------------------------------
660  *
661  * propagate
662  *
663  * make decision and propagate to all rules
664  *
665  * Evaluate each term affected by the decision (linked through watches).
666  * If we find unit rules we make new decisions based on them.
667  *
668  * return : 0 = everything is OK
669  *          rule = conflict found in this rule
670  */
671
672 static Rule *
673 propagate(Solver *solv, int level)
674 {
675   Pool *pool = solv->pool;
676   Id *rp, *next_rp;           /* rule pointer, next rule pointer in linked list */
677   Rule *r;                    /* rule */
678   Id p, pkg, other_watch;
679   Id *dp;
680   Id *decisionmap = solv->decisionmap;
681
682   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
683
684   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
685
686   /* foreach non-propagated decision */
687   while (solv->propagate_index < solv->decisionq.count)
688     {
689         /*
690          * 'pkg' was just decided
691          * negate because our watches trigger if literal goes FALSE
692          */
693       pkg = -solv->decisionq.elements[solv->propagate_index++];
694         
695       IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
696         {
697           POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
698           solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
699         }
700
701       /* foreach rule where 'pkg' is now FALSE */
702       for (rp = watches + pkg; *rp; rp = next_rp)
703         {
704           r = solv->rules + *rp;
705           if (r->d < 0)
706             {
707               /* rule is disabled, goto next */
708               if (pkg == r->w1)
709                 next_rp = &r->n1;
710               else
711                 next_rp = &r->n2;
712               continue;
713             }
714
715           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
716             {
717               POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
718               solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
719             }
720
721             /* 'pkg' was just decided (was set to FALSE)
722              *
723              *  now find other literal watch, check clause
724              *   and advance on linked list
725              */
726           if (pkg == r->w1)
727             {
728               other_watch = r->w2;
729               next_rp = &r->n1;
730             }
731           else
732             {
733               other_watch = r->w1;
734               next_rp = &r->n2;
735             }
736
737             /*
738              * This term is already true (through the other literal)
739              * so we have nothing to do
740              */
741           if (DECISIONMAP_TRUE(other_watch))
742             continue;
743
744             /*
745              * The other literal is FALSE or UNDEF
746              *
747              */
748
749           if (r->d)
750             {
751               /* Not a binary clause, try to move our watch.
752                *
753                * Go over all literals and find one that is
754                *   not other_watch
755                *   and not FALSE
756                *
757                * (TRUE is also ok, in that case the rule is fulfilled)
758                */
759               if (r->p                                /* we have a 'p' */
760                   && r->p != other_watch              /* which is not watched */
761                   && !DECISIONMAP_FALSE(r->p))        /* and not FALSE */
762                 {
763                   p = r->p;
764                 }
765               else                                    /* go find a 'd' to make 'true' */
766                 {
767                   /* foreach p in 'd'
768                      we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself
769                    */
770                   for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
771                     {
772                       if (p != other_watch              /* which is not watched */
773                           && !DECISIONMAP_FALSE(p))     /* and not FALSE */
774                         break;
775                     }
776                 }
777
778               if (p)
779                 {
780                   /*
781                    * if we found some p that is UNDEF or TRUE, move
782                    * watch to it
783                    */
784                   IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
785                     {
786                       if (p > 0)
787                         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
788                       else
789                         POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
790                     }
791
792                   *rp = *next_rp;
793                   next_rp = rp;
794
795                   if (pkg == r->w1)
796                     {
797                       r->w1 = p;
798                       r->n1 = watches[p];
799                     }
800                   else
801                     {
802                       r->w2 = p;
803                       r->n2 = watches[p];
804                     }
805                   watches[p] = r - solv->rules;
806                   continue;
807                 }
808               /* search failed, thus all unwatched literals are FALSE */
809                 
810             } /* not binary */
811
812           /*
813            * unit clause found, set literal other_watch to TRUE
814            */
815
816           if (DECISIONMAP_FALSE(other_watch))      /* check if literal is FALSE */
817             return r;                              /* eek, a conflict! */
818
819           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
820             {
821               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "  unit ");
822               solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
823             }
824
825           if (other_watch > 0)
826             decisionmap[other_watch] = level;    /* install! */
827           else
828             decisionmap[-other_watch] = -level;  /* remove! */
829
830           queue_push(&solv->decisionq, other_watch);
831           queue_push(&solv->decisionq_why, r - solv->rules);
832
833           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
834             {
835               if (other_watch > 0)
836                 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to install %s\n", pool_solvid2str(pool, other_watch));
837               else
838                 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", pool_solvid2str(pool, -other_watch));
839             }
840
841         } /* foreach rule involving 'pkg' */
842         
843     } /* while we have non-decided decisions */
844
845   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
846
847   return 0;     /* all is well */
848 }
849
850
851 /********************************************************************/
852 /* Analysis */
853
854 /*-------------------------------------------------------------------
855  *
856  * analyze
857  *   and learn
858  */
859
860 static int
861 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
862 {
863   Pool *pool = solv->pool;
864   Queue r;
865   Id r_buf[4];
866   int rlevel = 1;
867   Map seen;             /* global? */
868   Id d, v, vv, *dp, why;
869   int l, i, idx;
870   int num = 0, l1num = 0;
871   int learnt_why = solv->learnt_pool.count;
872   Id *decisionmap = solv->decisionmap;
873
874   queue_init_buffer(&r, r_buf, sizeof(r_buf)/sizeof(*r_buf));
875
876   POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
877   map_init(&seen, pool->nsolvables);
878   idx = solv->decisionq.count;
879   for (;;)
880     {
881       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
882         solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c);
883       queue_push(&solv->learnt_pool, c - solv->rules);
884       d = c->d < 0 ? -c->d - 1 : c->d;
885       dp = d ? pool->whatprovidesdata + d : 0;
886       /* go through all literals of the rule */
887       for (i = -1; ; i++)
888         {
889           if (i == -1)
890             v = c->p;
891           else if (d == 0)
892             v = i ? 0 : c->w2;
893           else
894             v = *dp++;
895           if (v == 0)
896             break;
897
898           if (DECISIONMAP_TRUE(v))      /* the one true literal */
899             continue;
900           vv = v > 0 ? v : -v;
901           if (MAPTST(&seen, vv))
902             continue;
903           l = solv->decisionmap[vv];
904           if (l < 0)
905             l = -l;
906           MAPSET(&seen, vv);            /* mark that we also need to look at this literal */
907           if (l == 1)
908             l1num++;                    /* need to do this one in level1 pass */
909           else if (l == level)
910             num++;                      /* need to do this one as well */
911           else
912             {
913               queue_push(&r, v);        /* not level1 or conflict level, add to new rule */
914               if (l > rlevel)
915                 rlevel = l;
916             }
917         }
918 l1retry:
919       if (!num && !--l1num)
920         break;  /* all level 1 literals done */
921
922       /* find the next literal to investigate */
923       /* (as num + l1num > 0, we know that we'll always find one) */
924       for (;;)
925         {
926           assert(idx > 0);
927           v = solv->decisionq.elements[--idx];
928           vv = v > 0 ? v : -v;
929           if (MAPTST(&seen, vv))
930             break;
931         }
932       MAPCLR(&seen, vv);
933
934       if (num && --num == 0)
935         {
936           *pr = -v;     /* so that v doesn't get lost */
937           if (!l1num)
938             break;
939           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
940           /* clear non-l1 bits from seen map */
941           for (i = 0; i < r.count; i++)
942             {
943               v = r.elements[i];
944               MAPCLR(&seen, v > 0 ? v : -v);
945             }
946           /* only level 1 marks left in seen map */
947           l1num++;      /* as l1retry decrements it */
948           goto l1retry;
949         }
950
951       why = solv->decisionq_why.elements[idx];
952       if (why <= 0)     /* just in case, maybe for SYSTEMSOLVABLE */
953         goto l1retry;
954       c = solv->rules + why;
955     }
956   map_free(&seen);
957
958   if (r.count == 0)
959     *dr = 0;
960   else if (r.count == 1 && r.elements[0] < 0)
961     *dr = r.elements[0];
962   else
963     *dr = pool_queuetowhatprovides(pool, &r);
964   IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
965     {
966       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
967       solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, *pr);
968       for (i = 0; i < r.count; i++)
969         solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, r.elements[i]);
970     }
971   /* push end marker on learnt reasons stack */
972   queue_push(&solv->learnt_pool, 0);
973   if (whyp)
974     *whyp = learnt_why;
975   queue_free(&r);
976   solv->stats_learned++;
977   return rlevel;
978 }
979
980
981 /*-------------------------------------------------------------------
982  *
983  * solver_reset
984  *
985  * reset all solver decisions
986  * called after rules have been enabled/disabled
987  */
988
989 void
990 solver_reset(Solver *solv)
991 {
992   Pool *pool = solv->pool;
993   int i;
994   Id v;
995
996   /* rewind all decisions */
997   for (i = solv->decisionq.count - 1; i >= 0; i--)
998     {
999       v = solv->decisionq.elements[i];
1000       solv->decisionmap[v > 0 ? v : -v] = 0;
1001     }
1002   queue_empty(&solv->decisionq_why);
1003   queue_empty(&solv->decisionq);
1004   solv->recommends_index = -1;
1005   solv->propagate_index = 0;
1006   solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
1007   queue_empty(&solv->branches);
1008
1009   /* adapt learnt rule status to new set of enabled/disabled rules */
1010   enabledisablelearntrules(solv);
1011
1012   /* redo all assertion rule decisions */
1013   makeruledecisions(solv);
1014   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
1015 }
1016
1017
1018 /*-------------------------------------------------------------------
1019  *
1020  * analyze_unsolvable_rule
1021  *
1022  * recursion helper used by analyze_unsolvable
1023  */
1024
1025 static void
1026 analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
1027 {
1028   Pool *pool = solv->pool;
1029   int i;
1030   Id why = r - solv->rules;
1031
1032   IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
1033     solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
1034   if (solv->learntrules && why >= solv->learntrules)
1035     {
1036       if (MAPTST(rseen, why - solv->learntrules))
1037         return;
1038       MAPSET(rseen, why - solv->learntrules);
1039       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
1040         if (solv->learnt_pool.elements[i] > 0)
1041           analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen);
1042       return;
1043     }
1044   if (MAPTST(&solv->weakrulemap, why))
1045     if (!*lastweakp || why > *lastweakp)
1046       *lastweakp = why;
1047   /* do not add pkg rules to problem */
1048   if (why < solv->pkgrules_end)
1049     return;
1050   /* turn rule into problem */
1051   if (why >= solv->jobrules && why < solv->jobrules_end)
1052     why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
1053   /* normalize dup/infarch rules */
1054   if (why > solv->infarchrules && why < solv->infarchrules_end)
1055     {
1056       Id name = pool->solvables[-solv->rules[why].p].name;
1057       while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
1058         why--;
1059     }
1060   if (why > solv->duprules && why < solv->duprules_end)
1061     {
1062       Id name = pool->solvables[-solv->rules[why].p].name;
1063       while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
1064         why--;
1065     }
1066
1067   /* return if problem already countains our rule */
1068   if (solv->problems.count)
1069     {
1070       for (i = solv->problems.count - 1; i >= 0; i--)
1071         if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
1072           break;
1073         else if (solv->problems.elements[i] == why)
1074           return;
1075     }
1076   queue_push(&solv->problems, why);
1077 }
1078
1079
1080 /*-------------------------------------------------------------------
1081  *
1082  * analyze_unsolvable
1083  *
1084  * We know that the problem is not solvable. Record all involved
1085  * rules (i.e. the "proof") into solv->learnt_pool.
1086  * Record the learnt pool index and all non-pkg rules into
1087  * solv->problems. (Our solutions to fix the problems are to
1088  * disable those rules.)
1089  *
1090  * If the proof contains at least one weak rule, we disable the
1091  * last of them.
1092  *
1093  * Otherwise we return 0 if disablerules is not set or disable
1094  * _all_ of the problem rules and return 1.
1095  *
1096  * return: 1 - disabled some rules, try again
1097  *         0 - hopeless
1098  */
1099
1100 static int
1101 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
1102 {
1103   Pool *pool = solv->pool;
1104   Rule *r;
1105   Map seen;             /* global to speed things up? */
1106   Map rseen;
1107   Id d, v, vv, *dp, why;
1108   int l, i, idx;
1109   Id *decisionmap = solv->decisionmap;
1110   int oldproblemcount;
1111   int oldlearntpoolcount;
1112   Id lastweak;
1113   int record_proof = 1;
1114
1115   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
1116   solv->stats_unsolvable++;
1117   oldproblemcount = solv->problems.count;
1118   oldlearntpoolcount = solv->learnt_pool.count;
1119
1120   /* make room for proof index */
1121   /* must update it later, as analyze_unsolvable_rule would confuse
1122    * it with a rule index if we put the real value in already */
1123   queue_push(&solv->problems, 0);
1124
1125   r = cr;
1126   map_init(&seen, pool->nsolvables);
1127   map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
1128   if (record_proof)
1129     queue_push(&solv->learnt_pool, r - solv->rules);
1130   lastweak = 0;
1131   analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1132   d = r->d < 0 ? -r->d - 1 : r->d;
1133   dp = d ? pool->whatprovidesdata + d : 0;
1134   for (i = -1; ; i++)
1135     {
1136       if (i == -1)
1137         v = r->p;
1138       else if (d == 0)
1139         v = i ? 0 : r->w2;
1140       else
1141         v = *dp++;
1142       if (v == 0)
1143         break;
1144       if (DECISIONMAP_TRUE(v))  /* the one true literal */
1145           continue;
1146       vv = v > 0 ? v : -v;
1147       l = solv->decisionmap[vv];
1148       if (l < 0)
1149         l = -l;
1150       MAPSET(&seen, vv);
1151     }
1152   idx = solv->decisionq.count;
1153   while (idx > 0)
1154     {
1155       v = solv->decisionq.elements[--idx];
1156       vv = v > 0 ? v : -v;
1157       if (!MAPTST(&seen, vv) || vv == SYSTEMSOLVABLE)
1158         continue;
1159       why = solv->decisionq_why.elements[idx];
1160       assert(why > 0);
1161       if (record_proof)
1162         queue_push(&solv->learnt_pool, why);
1163       r = solv->rules + why;
1164       analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1165       d = r->d < 0 ? -r->d - 1 : r->d;
1166       dp = d ? pool->whatprovidesdata + d : 0;
1167       for (i = -1; ; i++)
1168         {
1169           if (i == -1)
1170             v = r->p;
1171           else if (d == 0)
1172             v = i ? 0 : r->w2;
1173           else
1174             v = *dp++;
1175           if (v == 0)
1176             break;
1177           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1178               continue;
1179           vv = v > 0 ? v : -v;
1180           l = solv->decisionmap[vv];
1181           if (l < 0)
1182             l = -l;
1183           MAPSET(&seen, vv);
1184         }
1185     }
1186   map_free(&seen);
1187   map_free(&rseen);
1188   queue_push(&solv->problems, 0);       /* mark end of this problem */
1189
1190   if (lastweak)
1191     {
1192       /* disable last weak rule */
1193       solv->problems.count = oldproblemcount;
1194       solv->learnt_pool.count = oldlearntpoolcount;
1195       if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
1196         v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
1197       else
1198         v = lastweak;
1199       POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
1200       solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
1201       if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
1202         solver_disablechoicerules(solv, solv->rules + lastweak);
1203       solver_disableproblem(solv, v);
1204       if (v < 0)
1205         solver_reenablepolicyrules(solv, -v);
1206       solver_reset(solv);
1207       return 1;
1208     }
1209
1210   if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
1211     {
1212       solv->problems.count = oldproblemcount;
1213       solv->learnt_pool.count = oldlearntpoolcount;
1214       solver_reset(solv);
1215       return 1;
1216     }
1217
1218   /* finish proof */
1219   if (record_proof)
1220     {
1221       queue_push(&solv->learnt_pool, 0);
1222       solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
1223     }
1224
1225   /* + 2: index + trailing zero */
1226   if (disablerules && oldproblemcount + 2 < solv->problems.count)
1227     {
1228       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1229         solver_disableproblem(solv, solv->problems.elements[i]);
1230       /* XXX: might want to enable all weak rules again */
1231       solver_reset(solv);
1232       return 1;
1233     }
1234   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
1235   return 0;
1236 }
1237
1238
1239 /********************************************************************/
1240 /* Decision revert */
1241
1242 /*-------------------------------------------------------------------
1243  *
1244  * revert
1245  * revert decisionq to a level
1246  */
1247
1248 static void
1249 revert(Solver *solv, int level)
1250 {
1251   Pool *pool = solv->pool;
1252   Id v, vv;
1253   while (solv->decisionq.count)
1254     {
1255       v = solv->decisionq.elements[solv->decisionq.count - 1];
1256       vv = v > 0 ? v : -v;
1257       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
1258         break;
1259       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
1260       solv->decisionmap[vv] = 0;
1261       solv->decisionq.count--;
1262       solv->decisionq_why.count--;
1263       solv->propagate_index = solv->decisionq.count;
1264     }
1265   while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= level)
1266     solv->branches.count -= solv->branches.elements[solv->branches.count - 2];
1267   if (solv->recommends_index > solv->decisionq.count)
1268     solv->recommends_index = -1;        /* rebuild recommends/suggests maps */
1269   if (solv->decisionq.count < solv->decisioncnt_jobs)
1270     solv->decisioncnt_jobs = 0;
1271   if (solv->decisionq.count < solv->decisioncnt_update)
1272     solv->decisioncnt_update = 0;
1273   if (solv->decisionq.count < solv->decisioncnt_keep)
1274     solv->decisioncnt_keep = 0;
1275   if (solv->decisionq.count < solv->decisioncnt_resolve)
1276     solv->decisioncnt_resolve = 0;
1277   if (solv->decisionq.count < solv->decisioncnt_weak)
1278     solv->decisioncnt_weak= 0;
1279   if (solv->decisionq.count < solv->decisioncnt_orphan)
1280     solv->decisioncnt_orphan = 0;
1281 }
1282
1283
1284 /*-------------------------------------------------------------------
1285  *
1286  * watch2onhighest - put watch2 on literal with highest level
1287  */
1288
1289 static inline void
1290 watch2onhighest(Solver *solv, Rule *r)
1291 {
1292   int l, wl = 0;
1293   Id d, v, *dp;
1294
1295   d = r->d < 0 ? -r->d - 1 : r->d;
1296   if (!d)
1297     return;     /* binary rule, both watches are set */
1298   dp = solv->pool->whatprovidesdata + d;
1299   while ((v = *dp++) != 0)
1300     {
1301       l = solv->decisionmap[v < 0 ? -v : v];
1302       if (l < 0)
1303         l = -l;
1304       if (l > wl)
1305         {
1306           r->w2 = dp[-1];
1307           wl = l;
1308         }
1309     }
1310 }
1311
1312
1313 /*-------------------------------------------------------------------
1314  *
1315  * setpropagatelearn
1316  *
1317  * add free decision (solvable to install) to decisionq
1318  * increase level and propagate decision
1319  * return if no conflict.
1320  *
1321  * in conflict case, analyze conflict rule, add resulting
1322  * rule to learnt rule set, make decision from learnt
1323  * rule (always unit) and re-propagate.
1324  *
1325  * returns the new solver level or 0 if unsolvable
1326  *
1327  */
1328
1329 static int
1330 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
1331 {
1332   Pool *pool = solv->pool;
1333   Rule *r;
1334   Id p = 0, d = 0;
1335   int l, why;
1336
1337   assert(ruleid >= 0);
1338   if (decision)
1339     {
1340       level++;
1341       if (decision > 0)
1342         solv->decisionmap[decision] = level;
1343       else
1344         solv->decisionmap[-decision] = -level;
1345       queue_push(&solv->decisionq, decision);
1346       queue_push(&solv->decisionq_why, -ruleid);        /* <= 0 -> free decision */
1347     }
1348   for (;;)
1349     {
1350       r = propagate(solv, level);
1351       if (!r)
1352         break;
1353       if (level == 1)
1354         return analyze_unsolvable(solv, r, disablerules);
1355       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
1356       l = analyze(solv, level, r, &p, &d, &why);        /* learnt rule in p and d */
1357       assert(l > 0 && l < level);
1358       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
1359       level = l;
1360       revert(solv, level);
1361       r = solver_addrule(solv, p, d);
1362       assert(r);
1363       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
1364       queue_push(&solv->learnt_why, why);
1365       if (d)
1366         {
1367           /* at least 2 literals, needs watches */
1368           watch2onhighest(solv, r);
1369           addwatches_rule(solv, r);
1370         }
1371       else
1372         {
1373           /* learnt rule is an assertion */
1374           queue_push(&solv->ruleassertions, r - solv->rules);
1375         }
1376       /* the new rule is unit by design */
1377       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
1378       queue_push(&solv->decisionq, p);
1379       queue_push(&solv->decisionq_why, r - solv->rules);
1380       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
1381         {
1382           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: ");
1383           solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
1384           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: ");
1385           solver_printrule(solv, SOLV_DEBUG_ANALYZE, r);
1386         }
1387     }
1388   return level;
1389 }
1390
1391 static void
1392 reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq)
1393 {
1394   Pool *pool = solv->pool;
1395   int i, j, haveone = 0, dqcount = dq->count;
1396   int decisionqcount = solv->decisionq.count;
1397   Id p;
1398   Solvable *s;
1399
1400   /* at the time we process jobrules the installed packages are not kept yet */
1401   /* reorder so that "future-supplemented" packages come first */
1402   FOR_REPO_SOLVABLES(solv->installed, p, s)
1403     {
1404       if (MAPTST(&solv->noupdate, p - solv->installed->start))
1405         continue;
1406       if (solv->decisionmap[p] == 0)
1407         {
1408           if (s->recommends || s->suggests)
1409             queue_push(&solv->decisionq, p);
1410           solv->decisionmap[p] = level + 1;
1411           haveone = 1;
1412         }
1413     }
1414   if (!haveone)
1415     return;
1416   policy_update_recommendsmap(solv);
1417   for (i = 0; i < dqcount; i++)
1418     {
1419       p = dq->elements[i];
1420       if (!(pool->solvables[p].repo == solv->installed || MAPTST(&solv->suggestsmap, p) || solver_is_enhancing(solv, pool->solvables + p)))
1421         {
1422           queue_push(dq, p);
1423           dq->elements[i] = 0;
1424         }
1425     }
1426   dqcount = dq->count;
1427   for (i = 0; i < dqcount; i++)
1428     {
1429       p = dq->elements[i];
1430       if (p && !(pool->solvables[p].repo == solv->installed || MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
1431         {
1432           queue_push(dq, p);
1433           dq->elements[i] = 0;
1434         }
1435     }
1436   for (i = j = 0; i < dq->count; i++)
1437     if (dq->elements[i])
1438       dq->elements[j++] = dq->elements[i];
1439   queue_truncate(dq, j);
1440   FOR_REPO_SOLVABLES(solv->installed, p, s)
1441     if (solv->decisionmap[p] == level + 1)
1442       solv->decisionmap[p] = 0;
1443   if (solv->decisionq.count != decisionqcount)
1444     {
1445       solv->recommends_index = -1;
1446       queue_truncate(&solv->decisionq, decisionqcount);
1447     }
1448 }
1449
1450 /*-------------------------------------------------------------------
1451  *
1452  * branch handling
1453  */
1454
1455 static void
1456 createbranch(Solver *solv, int level, Queue *dq, Id p, Id data)
1457 {
1458   Pool *pool = solv->pool;
1459   int i;
1460   IF_POOLDEBUG (SOLV_DEBUG_POLICY)
1461     {
1462       POOL_DEBUG (SOLV_DEBUG_POLICY, "creating a branch:\n");
1463       for (i = 0; i < dq->count; i++)
1464         POOL_DEBUG (SOLV_DEBUG_POLICY, "  - %s\n", pool_solvid2str(pool, dq->elements[i]));
1465     }
1466   queue_push(&solv->branches, -dq->elements[0]);
1467   for (i = 1; i < dq->count; i++)
1468     queue_push(&solv->branches, dq->elements[i]);
1469   queue_push2(&solv->branches, p, data);
1470   queue_push2(&solv->branches, dq->count + 4, level);
1471 }
1472
1473 static int
1474 takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
1475 {
1476   Pool *pool = solv->pool;
1477   int level;
1478   Id p, why;
1479 #if 0
1480   {
1481     int i;
1482     printf("branch group level %d [%d-%d] %d %d:\n", solv->branches.elements[end - 1], start, end, solv->branches.elements[end - 4], solv->branches.elements[end - 3]);
1483     for (i = end - solv->branches.elements[end - 2]; i < end - 4; i++)
1484       printf("%c %c%s\n", i == pos ? 'x' : ' ', solv->branches.elements[i] >= 0 ? ' ' : '-', pool_solvid2str(pool, solv->branches.elements[i] >= 0 ? solv->branches.elements[i] : -solv->branches.elements[i]));
1485   }
1486 #endif
1487   level = solv->branches.elements[end - 1];
1488   p = solv->branches.elements[pos];
1489   solv->branches.elements[pos] = -p;
1490   POOL_DEBUG(SOLV_DEBUG_SOLVER, "%s %d -> %d with %s\n", msg, solv->decisionmap[p], level, pool_solvid2str(pool, p));
1491   /* hack: set level to zero so that revert does not remove the branch */
1492   solv->branches.elements[end - 1] = 0;
1493   revert(solv, level);
1494   solv->branches.elements[end - 1] = level;
1495   /* hack: revert simply sets the count, so we can still access the reverted elements */
1496   why = -solv->decisionq_why.elements[solv->decisionq_why.count];
1497   assert(why >= 0);
1498   return setpropagatelearn(solv, level, p, disablerules, why);
1499 }
1500
1501 /*-------------------------------------------------------------------
1502  *
1503  * select and install
1504  *
1505  * install best package from the queue. We add an extra package, inst, if
1506  * provided. See comment in weak install section.
1507  *
1508  * returns the new solver level or 0 if unsolvable
1509  *
1510  */
1511
1512 static int
1513 selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid)
1514 {
1515   Pool *pool = solv->pool;
1516   Id p;
1517
1518   if (dq->count > 1)
1519     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
1520   /* if we're resolving job rules and didn't resolve the installed packages yet,
1521    * do some special supplements ordering */
1522   if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed && !solv->focus_installed)
1523     reorder_dq_for_jobrules(solv, level, dq);
1524   /* if we have multiple candidates we open a branch */
1525   if (dq->count > 1)
1526     createbranch(solv, level, dq, 0, ruleid);
1527   p = dq->elements[0];
1528   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p));
1529   return setpropagatelearn(solv, level, p, disablerules, ruleid);
1530 }
1531
1532
1533 /********************************************************************/
1534 /* Main solver interface */
1535
1536
1537 /*-------------------------------------------------------------------
1538  *
1539  * solver_create
1540  * create solver structure
1541  *
1542  * pool: all available solvables
1543  * installed: installed Solvables
1544  *
1545  *
1546  * Upon solving, rules are created to flag the Solvables
1547  * of the 'installed' Repo as installed.
1548  */
1549
1550 Solver *
1551 solver_create(Pool *pool)
1552 {
1553   Solver *solv;
1554   solv = (Solver *)solv_calloc(1, sizeof(Solver));
1555   solv->pool = pool;
1556   solv->installed = pool->installed;
1557
1558   solv->allownamechange = 1;
1559
1560   solv->dup_allowdowngrade = 1;
1561   solv->dup_allownamechange = 1;
1562   solv->dup_allowarchchange = 1;
1563   solv->dup_allowvendorchange = 1;
1564
1565   solv->keepexplicitobsoletes = pool->noobsoletesmultiversion ? 0 : 1;
1566
1567   queue_init(&solv->ruletojob);
1568   queue_init(&solv->decisionq);
1569   queue_init(&solv->decisionq_why);
1570   queue_init(&solv->problems);
1571   queue_init(&solv->orphaned);
1572   queue_init(&solv->learnt_why);
1573   queue_init(&solv->learnt_pool);
1574   queue_init(&solv->branches);
1575   queue_init(&solv->weakruleq);
1576   queue_init(&solv->ruleassertions);
1577   queue_init(&solv->addedmap_deduceq);
1578
1579   queue_push(&solv->learnt_pool, 0);    /* so that 0 does not describe a proof */
1580
1581   map_init(&solv->recommendsmap, pool->nsolvables);
1582   map_init(&solv->suggestsmap, pool->nsolvables);
1583   map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0);
1584   solv->recommends_index = 0;
1585
1586   solv->decisionmap = (Id *)solv_calloc(pool->nsolvables, sizeof(Id));
1587   solv->nrules = 1;
1588   solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
1589   memset(solv->rules, 0, sizeof(Rule));
1590
1591   return solv;
1592 }
1593
1594
1595 static int
1596 resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
1597 {
1598   Pool *pool = solv->pool;
1599   int oldlevel = level;
1600   int i, olevel;
1601   Rule *r;
1602
1603   POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
1604   if (!solv->decisioncnt_jobs)
1605     solv->decisioncnt_jobs = solv->decisionq.count;
1606   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
1607     {
1608       Id l, pp;
1609       if (r->d < 0)             /* ignore disabled rules */
1610         continue;
1611       queue_empty(dq);
1612       FOR_RULELITERALS(l, pp, r)
1613         {
1614           if (l < 0)
1615             {
1616               if (solv->decisionmap[-l] <= 0)
1617                 break;
1618             }
1619           else
1620             {
1621               if (solv->decisionmap[l] > 0)
1622                 break;
1623               if (solv->decisionmap[l] == 0)
1624                 queue_push(dq, l);
1625             }
1626         }
1627       if (l || !dq->count)
1628         continue;
1629       /* prune to installed if not updating */
1630       if (dq->count > 1 && solv->installed && !solv->updatemap_all &&
1631           !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
1632         {
1633           int j, k;
1634           for (j = k = 0; j < dq->count; j++)
1635             {
1636               Solvable *s = pool->solvables + dq->elements[j];
1637               if (s->repo == solv->installed)
1638                 {
1639                   dq->elements[k++] = dq->elements[j];
1640                   if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start))
1641                     {
1642                       k = 0;    /* package wants to be updated, do not prune */
1643                       break;
1644                     }
1645                 }
1646             }
1647           if (k)
1648             dq->count = k;
1649         }
1650       olevel = level;
1651       level = selectandinstall(solv, level, dq, disablerules, i);
1652       if (level <= olevel)
1653         {
1654           if (level == 0)
1655             return 0;   /* unsolvable */
1656           if (level == olevel)
1657             {
1658               i--;
1659               r--;
1660               continue; /* try something else */
1661             }
1662           if (level < oldlevel)
1663             return level;
1664           /* redo from start of jobrules */
1665           i = solv->jobrules - 1;
1666           r = solv->rules + i;
1667         }
1668     }
1669   return level;
1670 }
1671
1672 /*-------------------------------------------------------------------
1673  *
1674  * solver_free
1675  */
1676
1677 static inline void
1678 queuep_free(Queue **qp)
1679 {
1680   if (!*qp)
1681     return;
1682   queue_free(*qp);
1683   *qp = solv_free(*qp);
1684 }
1685
1686 static inline void
1687 map_zerosize(Map *m)
1688 {
1689   if (m->size)
1690     {
1691       map_free(m);
1692       map_init(m, 0);
1693     }
1694 }
1695
1696 void
1697 solver_free(Solver *solv)
1698 {
1699   queue_free(&solv->job);
1700   queue_free(&solv->ruletojob);
1701   queue_free(&solv->decisionq);
1702   queue_free(&solv->decisionq_why);
1703   queue_free(&solv->learnt_why);
1704   queue_free(&solv->learnt_pool);
1705   queue_free(&solv->problems);
1706   queue_free(&solv->solutions);
1707   queue_free(&solv->orphaned);
1708   queue_free(&solv->branches);
1709   queue_free(&solv->weakruleq);
1710   queue_free(&solv->ruleassertions);
1711   queue_free(&solv->addedmap_deduceq);
1712   queuep_free(&solv->cleandeps_updatepkgs);
1713   queuep_free(&solv->cleandeps_mistakes);
1714   queuep_free(&solv->update_targets);
1715   queuep_free(&solv->installsuppdepq);
1716   queuep_free(&solv->recommendscplxq);
1717   queuep_free(&solv->suggestscplxq);
1718   queuep_free(&solv->brokenorphanrules);
1719
1720   map_free(&solv->recommendsmap);
1721   map_free(&solv->suggestsmap);
1722   map_free(&solv->noupdate);
1723   map_free(&solv->weakrulemap);
1724   map_free(&solv->multiversion);
1725
1726   map_free(&solv->updatemap);
1727   map_free(&solv->bestupdatemap);
1728   map_free(&solv->fixmap);
1729   map_free(&solv->dupmap);
1730   map_free(&solv->dupinvolvedmap);
1731   map_free(&solv->droporphanedmap);
1732   map_free(&solv->cleandepsmap);
1733
1734   solv_free(solv->decisionmap);
1735   solv_free(solv->rules);
1736   solv_free(solv->watches);
1737   solv_free(solv->obsoletes);
1738   solv_free(solv->obsoletes_data);
1739   solv_free(solv->specialupdaters);
1740   solv_free(solv->choicerules_ref);
1741   solv_free(solv->bestrules_pkg);
1742   solv_free(solv->yumobsrules_info);
1743   solv_free(solv->instbuddy);
1744   solv_free(solv);
1745 }
1746
1747 int
1748 solver_get_flag(Solver *solv, int flag)
1749 {
1750   switch (flag)
1751   {
1752   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1753     return solv->allowdowngrade;
1754   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1755     return solv->allownamechange;
1756   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1757     return solv->allowarchchange;
1758   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1759     return solv->allowvendorchange;
1760   case SOLVER_FLAG_ALLOW_UNINSTALL:
1761     return solv->allowuninstall;
1762   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1763     return solv->noupdateprovide;
1764   case SOLVER_FLAG_SPLITPROVIDES:
1765     return solv->dosplitprovides;
1766   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1767     return solv->dontinstallrecommended;
1768   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1769     return solv->addalreadyrecommended;
1770   case SOLVER_FLAG_NO_INFARCHCHECK:
1771     return solv->noinfarchcheck;
1772   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1773     return solv->keepexplicitobsoletes;
1774   case SOLVER_FLAG_BEST_OBEY_POLICY:
1775     return solv->bestobeypolicy;
1776   case SOLVER_FLAG_NO_AUTOTARGET:
1777     return solv->noautotarget;
1778   case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
1779     return solv->dup_allowdowngrade;
1780   case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
1781     return solv->dup_allownamechange;
1782   case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
1783     return solv->dup_allowarchchange;
1784   case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
1785     return solv->dup_allowvendorchange;
1786   case SOLVER_FLAG_KEEP_ORPHANS:
1787     return solv->keep_orphans;
1788   case SOLVER_FLAG_BREAK_ORPHANS:
1789     return solv->break_orphans;
1790   case SOLVER_FLAG_FOCUS_INSTALLED:
1791     return solv->focus_installed;
1792   case SOLVER_FLAG_YUM_OBSOLETES:
1793     return solv->do_yum_obsoletes;
1794   default:
1795     break;
1796   }
1797   return -1;
1798 }
1799
1800 int
1801 solver_set_flag(Solver *solv, int flag, int value)
1802 {
1803   int old = solver_get_flag(solv, flag);
1804   switch (flag)
1805   {
1806   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1807     solv->allowdowngrade = value;
1808     break;
1809   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1810     solv->allownamechange = value;
1811     break;
1812   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1813     solv->allowarchchange = value;
1814     break;
1815   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1816     solv->allowvendorchange = value;
1817     break;
1818   case SOLVER_FLAG_ALLOW_UNINSTALL:
1819     solv->allowuninstall = value;
1820     break;
1821   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1822     solv->noupdateprovide = value;
1823     break;
1824   case SOLVER_FLAG_SPLITPROVIDES:
1825     solv->dosplitprovides = value;
1826     break;
1827   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1828     solv->dontinstallrecommended = value;
1829     break;
1830   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1831     solv->addalreadyrecommended = value;
1832     break;
1833   case SOLVER_FLAG_NO_INFARCHCHECK:
1834     solv->noinfarchcheck = value;
1835     break;
1836   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1837     solv->keepexplicitobsoletes = value;
1838     break;
1839   case SOLVER_FLAG_BEST_OBEY_POLICY:
1840     solv->bestobeypolicy = value;
1841     break;
1842   case SOLVER_FLAG_NO_AUTOTARGET:
1843     solv->noautotarget = value;
1844     break;
1845   case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
1846     solv->dup_allowdowngrade = value;
1847     break;
1848   case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
1849     solv->dup_allownamechange = value;
1850     break;
1851   case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
1852     solv->dup_allowarchchange = value;
1853     break;
1854   case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
1855     solv->dup_allowvendorchange = value;
1856     break;
1857   case SOLVER_FLAG_KEEP_ORPHANS:
1858     solv->keep_orphans = value;
1859     break;
1860   case SOLVER_FLAG_BREAK_ORPHANS:
1861     solv->break_orphans = value;
1862     break;
1863   case SOLVER_FLAG_FOCUS_INSTALLED:
1864     solv->focus_installed = value;
1865     break;
1866   case SOLVER_FLAG_YUM_OBSOLETES:
1867     solv->do_yum_obsoletes = value;
1868     break;
1869   default:
1870     break;
1871   }
1872   return old;
1873 }
1874
1875 int
1876 cleandeps_check_mistakes(Solver *solv, int level)
1877 {
1878   Pool *pool = solv->pool;
1879   Rule *r;
1880   Id p, pp;
1881   int i;
1882   int mademistake = 0;
1883
1884   if (!solv->cleandepsmap.size)
1885     return 0;
1886   /* check for mistakes */
1887   for (i = solv->installed->start; i < solv->installed->end; i++)
1888     {
1889       if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1890         continue;
1891       r = solv->rules + solv->featurerules + (i - solv->installed->start);
1892       /* a mistake is when the featurerule is true but the updaterule is false */
1893       if (!r->p)
1894         continue;
1895       FOR_RULELITERALS(p, pp, r)
1896         if (p > 0 && solv->decisionmap[p] > 0)
1897           break;
1898       if (!p)
1899         continue;       /* feature rule is not true */
1900       r = solv->rules + solv->updaterules + (i - solv->installed->start);
1901       if (!r->p)
1902         continue;
1903       FOR_RULELITERALS(p, pp, r)
1904         if (p > 0 && solv->decisionmap[p] > 0)
1905           break;
1906       if (p)
1907         continue;       /* update rule is true */
1908       POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
1909       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
1910       POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
1911       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start));
1912       if (!solv->cleandeps_mistakes)
1913         {
1914           solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
1915           queue_init(solv->cleandeps_mistakes);
1916         }
1917       queue_push(solv->cleandeps_mistakes, i);
1918       MAPCLR(&solv->cleandepsmap, i - solv->installed->start);
1919       solver_reenablepolicyrules_cleandeps(solv, i);
1920       mademistake = 1;
1921     }
1922   if (mademistake)
1923     solver_reset(solv);
1924   return mademistake;
1925 }
1926
1927 static void
1928 prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
1929 {
1930   int i, j;
1931   Id p, *cp2;
1932   for (i = j = 0; i < q->count; i++)
1933     {
1934       p = q->elements[i];
1935       for (cp2 = cp; *cp2; cp2++)
1936         if (*cp2 == p)
1937           {
1938             q->elements[j++] = p;
1939             break;
1940           }
1941     }
1942   queue_truncate(q, j);
1943 }
1944
1945 #ifdef ENABLE_COMPLEX_DEPS
1946
1947 static void
1948 add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap)
1949 {
1950   Pool *pool = solv->pool;
1951   int oldcnt = dq->count;
1952   int cutcnt, blkcnt;
1953   Id p;
1954   int i, j;
1955
1956 #if 0
1957   printf("ADD_COMPLEX_RECOMMENDS %s\n", pool_dep2str(pool, rec));
1958 #endif
1959   i = pool_normalize_complex_dep(pool, rec, dq, CPLXDEPS_EXPAND);
1960   if (i == 0 || i == 1)
1961     return;
1962   cutcnt = dq->count;
1963   for (i = oldcnt; i < cutcnt; i++)
1964     {
1965       blkcnt = dq->count;
1966       for (; (p = dq->elements[i]) != 0; i++)
1967         {
1968           if (p < 0)
1969             {
1970               if (solv->decisionmap[-p] <= 0)
1971                 break;
1972               continue;
1973             }
1974           if (solv->decisionmap[p] > 0)
1975             {
1976               queue_truncate(dq, blkcnt);
1977               break;
1978             }
1979           if (dqmap)
1980             {
1981               if (!MAPTST(dqmap, p))
1982                 continue;
1983             }
1984           else
1985             {
1986               if (solv->decisionmap[p] < 0)
1987                 continue;
1988               if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
1989                 continue;
1990             }
1991           queue_push(dq, p);
1992         }
1993       while (dq->elements[i])
1994         i++;
1995     }
1996   queue_deleten(dq, oldcnt, cutcnt - oldcnt);
1997   /* unify */
1998   if (dq->count != oldcnt)
1999     {
2000       for (j = oldcnt; j < dq->count; j++)
2001         {
2002           p = dq->elements[j];
2003           for (i = 0; i < j; i++)
2004             if (dq->elements[i] == p)
2005               {
2006                 dq->elements[j] = 0;
2007                 break;
2008               }
2009         }
2010       for (i = j = oldcnt; j < dq->count; j++)
2011         if (dq->elements[j])
2012           dq->elements[i++] = dq->elements[j];
2013       queue_truncate(dq, i);
2014     }
2015 #if 0
2016   printf("RETURN:\n");
2017   for (i = oldcnt; i < dq->count; i++)
2018     printf("  - %s\n", pool_solvid2str(pool, dq->elements[i]));
2019 #endif
2020 }
2021
2022 static void
2023 do_complex_recommendations(Solver *solv, Id rec, Map *m, int noselected)
2024 {
2025   Pool *pool = solv->pool;
2026   Queue dq;
2027   Id p;
2028   int i, blk;
2029
2030 #if 0
2031   printf("DO_COMPLEX_RECOMMENDATIONS %s\n", pool_dep2str(pool, rec));
2032 #endif
2033   queue_init(&dq);
2034   i = pool_normalize_complex_dep(pool, rec, &dq, CPLXDEPS_EXPAND);
2035   if (i == 0 || i == 1)
2036     {
2037       queue_free(&dq);
2038       return;
2039     }
2040   for (i = 0; i < dq.count; i++)
2041     {
2042       blk = i;
2043       for (; (p = dq.elements[i]) != 0; i++)
2044         {
2045           if (p < 0)
2046             {
2047               if (solv->decisionmap[-p] <= 0)
2048                 break;
2049               continue;
2050             }
2051           if (solv->decisionmap[p] > 0)
2052             {
2053               if (noselected)
2054                 break;
2055               MAPSET(m, p);
2056               for (i++; (p = dq.elements[i]) != 0; i++)
2057                 if (p > 0 && solv->decisionmap[p] > 0)
2058                   MAPSET(m, p);
2059               p = 1;
2060               break;
2061             }
2062         }
2063       if (!p)
2064         {
2065           for (i = blk; (p = dq.elements[i]) != 0; i++)
2066             if (p > 0)
2067               MAPSET(m, p);
2068         }
2069       while (dq.elements[i])
2070         i++;
2071     }
2072   queue_free(&dq);
2073 }
2074
2075 #endif
2076
2077 /*-------------------------------------------------------------------
2078  *
2079  * solver_run_sat
2080  *
2081  * all rules have been set up, now actually run the solver
2082  *
2083  */
2084
2085 void
2086 solver_run_sat(Solver *solv, int disablerules, int doweak)
2087 {
2088   Queue dq;             /* local decisionqueue */
2089   Queue dqs;            /* local decisionqueue for supplements */
2090   int systemlevel;
2091   int level, olevel;
2092   Rule *r;
2093   int i, j, n;
2094   Solvable *s;
2095   Pool *pool = solv->pool;
2096   Id p, pp, *dp;
2097   int minimizationsteps;
2098   int installedpos = solv->installed ? solv->installed->start : 0;
2099
2100   IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
2101     {
2102       POOL_DEBUG (SOLV_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
2103       for (i = 1; i < solv->nrules; i++)
2104         solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i);
2105     }
2106
2107   POOL_DEBUG(SOLV_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count);
2108
2109   /* start SAT algorithm */
2110   level = 1;
2111   systemlevel = level + 1;
2112   POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n");
2113
2114   queue_init(&dq);
2115   queue_init(&dqs);
2116
2117   /*
2118    * here's the main loop:
2119    * 1) propagate new decisions (only needed once)
2120    * 2) fulfill jobs
2121    * 3) try to keep installed packages
2122    * 4) fulfill all unresolved rules
2123    * 5) install recommended packages
2124    * 6) minimalize solution if we had choices
2125    * if we encounter a problem, we rewind to a safe level and restart
2126    * with step 1
2127    */
2128
2129   minimizationsteps = 0;
2130   for (;;)
2131     {
2132       /*
2133        * initial propagation of the assertions
2134        */
2135       if (level == 1)
2136         {
2137           POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
2138           if ((r = propagate(solv, level)) != 0)
2139             {
2140               if (analyze_unsolvable(solv, r, disablerules))
2141                 continue;
2142               level = 0;
2143               break;    /* unsolvable */
2144             }
2145         }
2146
2147       /*
2148        * resolve jobs first (unless focus_installed is set)
2149        */
2150      if (level < systemlevel && !solv->focus_installed)
2151         {
2152           olevel = level;
2153           level = resolve_jobrules(solv, level, disablerules, &dq);
2154           if (level < olevel)
2155             {
2156               if (level == 0)
2157                 break;  /* unsolvable */
2158               continue;
2159             }
2160           systemlevel = level + 1;
2161         }
2162
2163
2164       /*
2165        * installed packages
2166        */
2167       if (!solv->decisioncnt_update)
2168         solv->decisioncnt_update = solv->decisionq.count;
2169       if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
2170         {
2171           Repo *installed = solv->installed;
2172           int pass;
2173
2174           POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
2175           /* we use two passes if we need to update packages
2176            * to create a better user experience */
2177           for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++)
2178             {
2179               int passlevel = level;
2180               Id *specialupdaters = solv->specialupdaters;
2181               if (pass == 1 && !solv->decisioncnt_keep)
2182                 solv->decisioncnt_keep = solv->decisionq.count;
2183               /* start with installedpos, the position that gave us problems the last time */
2184               for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
2185                 {
2186                   Rule *rr;
2187                   Id d;
2188
2189                   if (i == installed->end)
2190                     i = installed->start;
2191                   s = pool->solvables + i;
2192                   if (s->repo != installed)
2193                     continue;
2194
2195                   if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start]))
2196                     continue;           /* already decided */
2197                   if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
2198                     continue;           /* updates first */
2199                   r = solv->rules + solv->updaterules + (i - installed->start);
2200                   rr = r;
2201                   if (!rr->p || rr->d < 0)      /* disabled -> look at feature rule */
2202                     rr -= solv->installed->end - solv->installed->start;
2203                   if (!rr->p)           /* identical to update rule? */
2204                     rr = r;
2205                   if (!rr->p && !(specialupdaters && specialupdaters[i - installed->start]))
2206                     continue;           /* orpaned package */
2207
2208                   /* check if we should update this package to the latest version
2209                    * noupdate is set for erase jobs, in that case we want to deinstall
2210                    * the installed package and not replace it with a newer version
2211                    * rr->p != i is for dup jobs where the installed package cannot be kept */
2212                   queue_empty(&dq);
2213                   if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i)))
2214                     {
2215                       if (!rr->p)
2216                         {
2217                           /* specialupdater with no update/feature rule */
2218                           for (d = specialupdaters[i - installed->start]; (p = pool->whatprovidesdata[d++]) != 0; )
2219                             {
2220                               if (solv->decisionmap[p] > 0)
2221                                 {
2222                                   dq.count = 0;
2223                                   break;
2224                                 }
2225                               if (!solv->decisionmap[p])
2226                                 queue_push(&dq, p);
2227                             }
2228                         }
2229                       else if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
2230                         {
2231                           /* special multiversion handling, make sure best version is chosen */
2232                           if (rr->p == i && solv->decisionmap[i] >= 0)
2233                             queue_push(&dq, i);
2234                           while ((p = pool->whatprovidesdata[d++]) != 0)
2235                             if (solv->decisionmap[p] >= 0)
2236                               queue_push(&dq, p);
2237                           if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
2238                             prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
2239                           if (dq.count)
2240                             {
2241                               policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
2242                               p = dq.elements[0];
2243                               if (p != i && solv->decisionmap[p] == 0)
2244                                 {
2245                                   rr = solv->rules + solv->featurerules + (i - solv->installed->start);
2246                                   if (!rr->p)           /* update rule == feature rule? */
2247                                     rr = rr - solv->featurerules + solv->updaterules;
2248                                   dq.count = 1;
2249                                 }
2250                               else
2251                                 dq.count = 0;
2252                             }
2253                         }
2254                       else
2255                         {
2256                           /* update to best package of the update rule */
2257                           FOR_RULELITERALS(p, pp, rr)
2258                             {
2259                               if (solv->decisionmap[p] > 0)
2260                                 {
2261                                   dq.count = 0;         /* already fulfilled */
2262                                   break;
2263                                 }
2264                               if (!solv->decisionmap[p])
2265                                 queue_push(&dq, p);
2266                             }
2267                         }
2268                     }
2269                   if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
2270                     prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
2271                   /* install best version */
2272                   if (dq.count)
2273                     {
2274                       olevel = level;
2275                       level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
2276                       if (level == 0)
2277                         {
2278                           queue_free(&dq);
2279                           queue_free(&dqs);
2280                           return;
2281                         }
2282                       if (level <= olevel)
2283                         {
2284                           if (level == 1 || level < passlevel)
2285                             break;      /* trouble */
2286                           if (level < olevel)
2287                             n = installed->start;       /* redo all */
2288                           i--;
2289                           n--;
2290                           continue;
2291                         }
2292                     }
2293                   /* if still undecided keep package */
2294                   if (solv->decisionmap[i] == 0)
2295                     {
2296                       olevel = level;
2297                       if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
2298                         {
2299 #if 0
2300                           POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
2301                           level = setpropagatelearn(solv, level, -i, disablerules, 0);
2302 #else
2303                           continue;
2304 #endif
2305                         }
2306                       else
2307                         {
2308                           POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
2309                           level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
2310                         }
2311                       if (level == 0)
2312                         break;
2313                       if (level <= olevel)
2314                         {
2315                           if (level == 1 || level < passlevel)
2316                             break;      /* trouble */
2317                           if (level < olevel)
2318                             n = installed->start;       /* redo all */
2319                           i--;
2320                           n--;
2321                           continue;     /* retry with learnt rule */
2322                         }
2323                     }
2324                 }
2325               if (n < installed->end)
2326                 {
2327                   installedpos = i;     /* retry problem solvable next time */
2328                   break;                /* ran into trouble */
2329                 }
2330               installedpos = installed->start;  /* reset installedpos */
2331             }
2332           if (level == 0)
2333             break;              /* unsolvable */
2334           systemlevel = level + 1;
2335           if (pass < 2)
2336             continue;           /* had trouble, retry */
2337         }
2338       if (!solv->decisioncnt_keep)
2339         solv->decisioncnt_keep = solv->decisionq.count;
2340
2341      if (level < systemlevel && solv->focus_installed)
2342         {
2343           olevel = level;
2344           level = resolve_jobrules(solv, level, disablerules, &dq);
2345           if (level < olevel)
2346             {
2347               if (level == 0)
2348                 break;  /* unsolvable */
2349               continue;
2350             }
2351           systemlevel = level + 1;
2352         }
2353
2354       if (level < systemlevel)
2355         systemlevel = level;
2356
2357       /*
2358        * decide
2359        */
2360       if (!solv->decisioncnt_resolve)
2361         solv->decisioncnt_resolve = solv->decisionq.count;
2362       POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
2363       for (i = 1, n = 1; n < solv->nrules; i++, n++)
2364         {
2365           if (i == solv->nrules)
2366             i = 1;
2367           r = solv->rules + i;
2368           if (r->d < 0)         /* ignore disabled rules */
2369             continue;
2370           if (r->p < 0)         /* most common cases first */
2371             {
2372               if (r->d == 0 || solv->decisionmap[-r->p] <= 0)
2373                 continue;
2374             }
2375           if (dq.count)
2376             queue_empty(&dq);
2377           if (r->d == 0)
2378             {
2379               /* binary or unary rule */
2380               /* need two positive undecided literals, r->p already checked above */
2381               if (r->w2 <= 0)
2382                 continue;
2383               if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
2384                 continue;
2385               queue_push(&dq, r->p);
2386               queue_push(&dq, r->w2);
2387             }
2388           else
2389             {
2390               /* make sure that
2391                * all negative literals are installed
2392                * no positive literal is installed
2393                * i.e. the rule is not fulfilled and we
2394                * just need to decide on the positive literals
2395                * (decisionmap[-r->p] for the r->p < 0 case is already checked above)
2396                */
2397               if (r->p >= 0)
2398                 {
2399                   if (solv->decisionmap[r->p] > 0)
2400                     continue;
2401                   if (solv->decisionmap[r->p] == 0)
2402                     queue_push(&dq, r->p);
2403                 }
2404               dp = pool->whatprovidesdata + r->d;
2405               while ((p = *dp++) != 0)
2406                 {
2407                   if (p < 0)
2408                     {
2409                       if (solv->decisionmap[-p] <= 0)
2410                         break;
2411                     }
2412                   else
2413                     {
2414                       if (solv->decisionmap[p] > 0)
2415                         break;
2416                       if (solv->decisionmap[p] == 0)
2417                         queue_push(&dq, p);
2418                     }
2419                 }
2420               if (p)
2421                 continue;
2422             }
2423           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
2424             {
2425               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
2426               solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
2427             }
2428           /* dq.count < 2 cannot happen as this means that
2429            * the rule is unit */
2430           assert(dq.count > 1);
2431
2432           /* prune to cleandeps packages */
2433           if (solv->cleandepsmap.size && solv->installed)
2434             {
2435               Repo *installed = solv->installed;
2436               for (j = 0; j < dq.count; j++)
2437                 if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start))
2438                   break;
2439               if (j < dq.count)
2440                 {
2441                   dq.elements[0] = dq.elements[j];
2442                   queue_truncate(&dq, 1);
2443                 }
2444             }
2445
2446           olevel = level;
2447           level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
2448           if (level == 0)
2449             break;              /* unsolvable */
2450           if (level < systemlevel || level == 1)
2451             break;              /* trouble */
2452           /* something changed, so look at all rules again */
2453           n = 0;
2454         }
2455
2456       if (n != solv->nrules)    /* ran into trouble? */
2457         {
2458           if (level == 0)
2459             break;              /* unsolvable */
2460           continue;             /* start over */
2461         }
2462
2463       /* decide leftover cleandeps packages */
2464       if (solv->cleandepsmap.size && solv->installed)
2465         {
2466           for (p = solv->installed->start; p < solv->installed->end; p++)
2467             {
2468               s = pool->solvables + p;
2469               if (s->repo != solv->installed)
2470                 continue;
2471               if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
2472                 {
2473                   POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
2474                   olevel = level;
2475                   level = setpropagatelearn(solv, level, -p, 0, 0);
2476                   if (level < olevel)
2477                     break;
2478                 }
2479             }
2480           if (p < solv->installed->end)
2481             continue;
2482         }
2483
2484       /* at this point we have a consistent system. now do the extras... */
2485
2486       if (!solv->decisioncnt_weak)
2487         solv->decisioncnt_weak = solv->decisionq.count;
2488       if (doweak)
2489         {
2490           int qcount;
2491
2492           POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
2493           queue_empty(&dq);     /* recommended packages */
2494           queue_empty(&dqs);    /* supplemented packages */
2495           for (i = 1; i < pool->nsolvables; i++)
2496             {
2497               if (solv->decisionmap[i] < 0)
2498                 continue;
2499               if (solv->decisionmap[i] > 0)
2500                 {
2501                   /* installed, check for recommends */
2502                   Id *recp, rec, pp, p;
2503                   s = pool->solvables + i;
2504                   if (!solv->addalreadyrecommended && s->repo == solv->installed)
2505                     continue;
2506                   /* XXX need to special case AND ? */
2507                   if (s->recommends)
2508                     {
2509                       recp = s->repo->idarraydata + s->recommends;
2510                       while ((rec = *recp++) != 0)
2511                         {
2512 #ifdef ENABLE_COMPLEX_DEPS
2513                           if (pool_is_complex_dep(pool, rec))
2514                             {
2515                               add_complex_recommends(solv, rec, &dq, 0);
2516                               continue;
2517                             }
2518 #endif
2519                           qcount = dq.count;
2520                           FOR_PROVIDES(p, pp, rec)
2521                             {
2522                               if (solv->decisionmap[p] > 0)
2523                                 {
2524                                   dq.count = qcount;
2525                                   break;
2526                                 }
2527                               else if (solv->decisionmap[p] == 0)
2528                                 {
2529                                   if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
2530                                     continue;
2531                                   queue_pushunique(&dq, p);
2532                                 }
2533                             }
2534                         }
2535                     }
2536                 }
2537               else
2538                 {
2539                   s = pool->solvables + i;
2540                   if (!s->supplements)
2541                     continue;
2542                   if (!pool_installable(pool, s))
2543                     continue;
2544                   if (!solver_is_supplementing(solv, s))
2545                     continue;
2546                   if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
2547                     continue;
2548                   queue_push(&dqs, i);
2549                 }
2550             }
2551
2552           /* filter out all packages obsoleted by installed packages */
2553           /* this is no longer needed if we have reverse obsoletes */
2554           if ((dqs.count || dq.count) && solv->installed)
2555             {
2556               Map obsmap;
2557               Id obs, *obsp, po, ppo;
2558
2559               map_init(&obsmap, pool->nsolvables);
2560               for (p = solv->installed->start; p < solv->installed->end; p++)
2561                 {
2562                   s = pool->solvables + p;
2563                   if (s->repo != solv->installed || !s->obsoletes)
2564                     continue;
2565                   if (solv->decisionmap[p] <= 0)
2566                     continue;
2567                   if (solv->multiversion.size && MAPTST(&solv->multiversion, p))
2568                     continue;
2569                   obsp = s->repo->idarraydata + s->obsoletes;
2570                   /* foreach obsoletes */
2571                   while ((obs = *obsp++) != 0)
2572                     FOR_PROVIDES(po, ppo, obs)
2573                       MAPSET(&obsmap, po);
2574                 }
2575               for (i = j = 0; i < dqs.count; i++)
2576                 if (!MAPTST(&obsmap, dqs.elements[i]))
2577                   dqs.elements[j++] = dqs.elements[i];
2578               dqs.count = j;
2579               for (i = j = 0; i < dq.count; i++)
2580                 if (!MAPTST(&obsmap, dq.elements[i]))
2581                   dq.elements[j++] = dq.elements[i];
2582               dq.count = j;
2583               map_free(&obsmap);
2584             }
2585
2586           /* filter out all already supplemented packages if requested */
2587           if (!solv->addalreadyrecommended && dqs.count)
2588             {
2589               /* turn off all new packages */
2590               for (i = 0; i < solv->decisionq.count; i++)
2591                 {
2592                   p = solv->decisionq.elements[i];
2593                   if (p < 0)
2594                     continue;
2595                   s = pool->solvables + p;
2596                   if (s->repo && s->repo != solv->installed)
2597                     solv->decisionmap[p] = -solv->decisionmap[p];
2598                 }
2599               /* filter out old supplements */
2600               for (i = j = 0; i < dqs.count; i++)
2601                 {
2602                   p = dqs.elements[i];
2603                   s = pool->solvables + p;
2604                   if (!s->supplements)
2605                     continue;
2606                   if (!solver_is_supplementing(solv, s))
2607                     dqs.elements[j++] = p;
2608                   else if (solv->installsuppdepq && solver_check_installsuppdepq(solv, s))
2609                     dqs.elements[j++] = p;
2610                 }
2611               dqs.count = j;
2612               /* undo turning off */
2613               for (i = 0; i < solv->decisionq.count; i++)
2614                 {
2615                   p = solv->decisionq.elements[i];
2616                   if (p < 0)
2617                     continue;
2618                   s = pool->solvables + p;
2619                   if (s->repo && s->repo != solv->installed)
2620                     solv->decisionmap[p] = -solv->decisionmap[p];
2621                 }
2622             }
2623
2624           /* multiversion doesn't mix well with supplements.
2625            * filter supplemented packages where we already decided
2626            * to install a different version (see bnc#501088) */
2627           if (dqs.count && solv->multiversion.size)
2628             {
2629               for (i = j = 0; i < dqs.count; i++)
2630                 {
2631                   p = dqs.elements[i];
2632                   if (MAPTST(&solv->multiversion, p))
2633                     {
2634                       Id p2, pp2;
2635                       s = pool->solvables + p;
2636                       FOR_PROVIDES(p2, pp2, s->name)
2637                         if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
2638                           break;
2639                       if (p2)
2640                         continue;       /* ignore this package */
2641                     }
2642                   dqs.elements[j++] = p;
2643                 }
2644               dqs.count = j;
2645             }
2646
2647           /* make dq contain both recommended and supplemented pkgs */
2648           if (dqs.count)
2649             {
2650               for (i = 0; i < dqs.count; i++)
2651                 queue_pushunique(&dq, dqs.elements[i]);
2652             }
2653
2654           if (dq.count)
2655             {
2656               Map dqmap;
2657               int decisioncount = solv->decisionq.count;
2658
2659               if (dq.count == 1)
2660                 {
2661                   /* simple case, just one package. no need to choose to best version */
2662                   p = dq.elements[0];
2663                   if (dqs.count)
2664                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2665                   else
2666                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2667                   level = setpropagatelearn(solv, level, p, 0, 0);
2668                   if (level == 0)
2669                     break;
2670                   continue;     /* back to main loop */
2671                 }
2672
2673               /* filter packages, this gives us the best versions */
2674               policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
2675
2676               /* create map of result */
2677               map_init(&dqmap, pool->nsolvables);
2678               for (i = 0; i < dq.count; i++)
2679                 MAPSET(&dqmap, dq.elements[i]);
2680
2681               /* install all supplemented packages */
2682               for (i = 0; i < dqs.count; i++)
2683                 {
2684                   p = dqs.elements[i];
2685                   if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
2686                     continue;
2687                   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2688                   olevel = level;
2689                   level = setpropagatelearn(solv, level, p, 0, 0);
2690                   if (level <= olevel)
2691                     break;
2692                 }
2693               if (i < dqs.count || solv->decisionq.count < decisioncount)
2694                 {
2695                   map_free(&dqmap);
2696                   if (level == 0)
2697                     break;
2698                   continue;
2699                 }
2700
2701               /* install all recommended packages */
2702               /* more work as we want to created branches if multiple
2703                * choices are valid */
2704               for (i = 0; i < decisioncount; i++)
2705                 {
2706                   Id rec, *recp, pp;
2707                   p = solv->decisionq.elements[i];
2708                   if (p < 0)
2709                     continue;
2710                   s = pool->solvables + p;
2711                   if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
2712                     continue;
2713                   if (!s->recommends)
2714                     continue;
2715                   recp = s->repo->idarraydata + s->recommends;
2716                   while ((rec = *recp++) != 0)
2717                     {
2718                       queue_empty(&dq);
2719 #ifdef ENABLE_COMPLEX_DEPS
2720                       if (pool_is_complex_dep(pool, rec))
2721                           add_complex_recommends(solv, rec, &dq, &dqmap);
2722                       else
2723 #endif
2724                       FOR_PROVIDES(p, pp, rec)
2725                         {
2726                           if (solv->decisionmap[p] > 0)
2727                             {
2728                               dq.count = 0;
2729                               break;
2730                             }
2731                           else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
2732                             queue_push(&dq, p);
2733                         }
2734                       if (!dq.count)
2735                         continue;
2736                       if (dq.count > 1)
2737                         policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
2738                       /* if we have multiple candidates we open a branch */
2739                       if (dq.count > 1)
2740                           createbranch(solv, level, &dq, s - pool->solvables, rec);
2741                       p = dq.elements[0];
2742                       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2743                       olevel = level;
2744                       level = setpropagatelearn(solv, level, p, 0, 0);
2745                       if (level <= olevel || solv->decisionq.count < decisioncount)
2746                         break;  /* we had to revert some decisions */
2747                     }
2748                   if (rec)
2749                     break;      /* had a problem above, quit loop */
2750                 }
2751               map_free(&dqmap);
2752               if (level == 0)
2753                 break;
2754               continue;         /* back to main loop so that all deps are checked */
2755             }
2756         }
2757
2758       if (!solv->decisioncnt_orphan)
2759         solv->decisioncnt_orphan = solv->decisionq.count;
2760       if (solv->dupmap_all && solv->installed)
2761         {
2762           int installedone = 0;
2763
2764           /* let's see if we can install some unsupported package */
2765           POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
2766           for (i = 0; i < solv->orphaned.count; i++)
2767             {
2768               p = solv->orphaned.elements[i];
2769               if (solv->decisionmap[p])
2770                 continue;       /* already decided */
2771               if (solv->droporphanedmap_all)
2772                 continue;
2773               if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
2774                 continue;
2775               POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
2776               olevel = level;
2777               level = setpropagatelearn(solv, level, p, 0, 0);
2778               installedone = 1;
2779               if (level < olevel)
2780                 break;
2781             }
2782           if (installedone || i < solv->orphaned.count)
2783             {
2784               if (level == 0)
2785                 break;
2786               continue;         /* back to main loop */
2787             }
2788           for (i = 0; i < solv->orphaned.count; i++)
2789             {
2790               p = solv->orphaned.elements[i];
2791               if (solv->decisionmap[p])
2792                 continue;       /* already decided */
2793               POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
2794               olevel = level;
2795               level = setpropagatelearn(solv, level, -p, 0, 0);
2796               if (level < olevel)
2797                 break;
2798             }
2799           if (i < solv->orphaned.count)
2800             {
2801               if (level == 0)
2802                 break;
2803               continue;         /* back to main loop */
2804             }
2805           if (solv->brokenorphanrules)
2806             {
2807               solver_check_brokenorphanrules(solv, &dq);
2808               if (dq.count)
2809                 {
2810                   policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
2811                   for (i = 0; i < dq.count; i++)
2812                     {
2813                       p = dq.elements[i];
2814                       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p));
2815                       olevel = level;
2816                       level = setpropagatelearn(solv, level, p, 0, 0);
2817                       if (level < olevel)
2818                         break;
2819                     }
2820                   if (level == 0)
2821                     break;
2822                   continue;
2823                 }
2824             }
2825         }
2826
2827      /* one final pass to make sure we decided all installed packages */
2828       if (solv->installed)
2829         {
2830           for (p = solv->installed->start; p < solv->installed->end; p++)
2831             {
2832               if (solv->decisionmap[p])
2833                 continue;       /* already decided */
2834               s = pool->solvables + p;
2835               if (s->repo != solv->installed)
2836                 continue;
2837               POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing unwanted %s\n", pool_solvid2str(pool, p));
2838               olevel = level;
2839               level = setpropagatelearn(solv, level, -p, 0, 0);
2840               if (level < olevel)
2841                 break;
2842             }
2843           if (p < solv->installed->end)
2844             {
2845               if (level == 0)
2846                 break;
2847               continue;         /* back to main loop */
2848             }
2849         }
2850
2851       if (solv->installed && solv->cleandepsmap.size)
2852         {
2853           if (cleandeps_check_mistakes(solv, level))
2854             {
2855               level = 1;        /* restart from scratch */
2856               systemlevel = level + 1;
2857               continue;
2858             }
2859         }
2860
2861       if (solv->solution_callback)
2862         {
2863           solv->solution_callback(solv, solv->solution_callback_data);
2864           if (solv->branches.count)
2865             {
2866               int l, endi = 0;
2867               p = l = 0;
2868               for (i = solv->branches.count - 1; i >= 0; i--)
2869                 {
2870                   p = solv->branches.elements[i];
2871                   if (p > 0 && !l)
2872                     {
2873                       endi = i + 1;
2874                       l = p;
2875                       i -= 3;   /* skip: p data count */
2876                     }
2877                   else if (p > 0)
2878                     break;
2879                   else if (p < 0)
2880                     l = 0;
2881                 }
2882               if (i >= 0)
2883                 {
2884                   while (i > 0 && solv->branches.elements[i - 1] > 0)
2885                     i--;
2886                   level = takebranch(solv, i, endi, "branching", disablerules);
2887                   if (level == 0)
2888                     break;
2889                   continue;
2890                 }
2891             }
2892           /* all branches done, we're finally finished */
2893           break;
2894         }
2895
2896       /* auto-minimization step */
2897       if (solv->branches.count)
2898         {
2899           int endi, lasti = -1, lastiend = -1;
2900           if (solv->recommends_index < solv->decisionq.count)
2901             policy_update_recommendsmap(solv);
2902           for (endi = solv->branches.count; endi > 0;)
2903             {
2904               int l, lastsi = -1, starti = endi - solv->branches.elements[endi - 2];
2905               l = solv->branches.elements[endi - 1];
2906               for (i = starti; i < endi - 4; i++)
2907                 {
2908                   p = solv->branches.elements[i];
2909                   if (p <= 0)
2910                     continue;
2911                   if (solv->decisionmap[p] > l)
2912                     {
2913                       lasti = i;
2914                       lastiend = endi;
2915                       lastsi = -1;
2916                       break;
2917                     }
2918                   if (lastsi < 0 && (MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
2919                     lastsi = i;
2920                 }
2921               if (lastsi >= 0)
2922                 {
2923                   /* we have a recommended package that could not be installed */
2924                   /* take it if our current selection is not recommended */
2925                   for (i = starti; i < endi - 4; i++)
2926                     {
2927                       p = -solv->branches.elements[i];
2928                       if (p <= 0 || solv->decisionmap[p] != l + 1)
2929                         continue;
2930                       if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
2931                         {
2932                           lasti = lastsi;
2933                           lastiend = endi;
2934                           break;
2935                         }
2936                     }
2937                 }
2938               endi = starti;
2939             }
2940           if (lasti >= 0)
2941             {
2942               minimizationsteps++;
2943               level = takebranch(solv, lasti, lastiend, "minimizing", disablerules);
2944               if (level == 0)
2945                 break;
2946               continue;         /* back to main loop */
2947             }
2948         }
2949       /* no minimization found, we're finally finished! */
2950       break;
2951     }
2952
2953   POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
2954
2955   POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
2956   queue_free(&dq);
2957   queue_free(&dqs);
2958   if (level == 0)
2959     {
2960       /* unsolvable */
2961       solv->decisioncnt_jobs = solv->decisionq.count;
2962       solv->decisioncnt_update = solv->decisionq.count;
2963       solv->decisioncnt_keep = solv->decisionq.count;
2964       solv->decisioncnt_resolve = solv->decisionq.count;
2965       solv->decisioncnt_weak = solv->decisionq.count;
2966       solv->decisioncnt_orphan = solv->decisionq.count;
2967     }
2968 #if 0
2969   solver_printdecisionq(solv, SOLV_DEBUG_RESULT);
2970 #endif
2971 }
2972
2973
2974 /*-------------------------------------------------------------------
2975  *
2976  * remove disabled conflicts
2977  *
2978  * purpose: update the decisionmap after some rules were disabled.
2979  * this is used to calculate the suggested/recommended package list.
2980  * Also returns a "removed" list to undo the discisionmap changes.
2981  */
2982
2983 static void
2984 removedisabledconflicts(Solver *solv, Queue *removed)
2985 {
2986   Pool *pool = solv->pool;
2987   int i, n;
2988   Id p, why, *dp;
2989   Id new;
2990   Rule *r;
2991   Id *decisionmap = solv->decisionmap;
2992
2993   queue_empty(removed);
2994   for (i = 0; i < solv->decisionq.count; i++)
2995     {
2996       p = solv->decisionq.elements[i];
2997       if (p > 0)
2998         continue;       /* conflicts only, please */
2999       why = solv->decisionq_why.elements[i];
3000       if (why == 0)
3001         {
3002           /* no rule involved, must be a orphan package drop */
3003           continue;
3004         }
3005       /* we never do conflicts on free decisions, so there
3006        * must have been an unit rule */
3007       assert(why > 0);
3008       r = solv->rules + why;
3009       if (r->d < 0 && decisionmap[-p])
3010         {
3011           /* rule is now disabled, remove from decisionmap */
3012           POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing conflict for package %s[%d]\n", pool_solvid2str(pool, -p), -p);
3013           queue_push(removed, -p);
3014           queue_push(removed, decisionmap[-p]);
3015           decisionmap[-p] = 0;
3016         }
3017     }
3018   if (!removed->count)
3019     return;
3020   /* we removed some confliced packages. some of them might still
3021    * be in conflict, so search for unit rules and re-conflict */
3022   new = 0;
3023   for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
3024     {
3025       if (i == solv->nrules)
3026         {
3027           i = 1;
3028           r = solv->rules + i;
3029         }
3030       if (r->d < 0)
3031         continue;
3032       if (!r->w2)
3033         {
3034           if (r->p < 0 && !decisionmap[-r->p])
3035             new = r->p;
3036         }
3037       else if (!r->d)
3038         {
3039           /* binary rule */
3040           if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
3041             new = r->p;
3042           else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
3043             new = r->w2;
3044         }
3045       else
3046         {
3047           if (r->p < 0 && decisionmap[-r->p] == 0)
3048             new = r->p;
3049           if (new || DECISIONMAP_FALSE(r->p))
3050             {
3051               dp = pool->whatprovidesdata + r->d;
3052               while ((p = *dp++) != 0)
3053                 {
3054                   if (new && p == new)
3055                     continue;
3056                   if (p < 0 && decisionmap[-p] == 0)
3057                     {
3058                       if (new)
3059                         {
3060                           new = 0;
3061                           break;
3062                         }
3063                       new = p;
3064                     }
3065                   else if (!DECISIONMAP_FALSE(p))
3066                     {
3067                       new = 0;
3068                       break;
3069                     }
3070                 }
3071             }
3072         }
3073       if (new)
3074         {
3075           POOL_DEBUG(SOLV_DEBUG_SOLVER, "re-conflicting package %s[%d]\n", pool_solvid2str(pool, -new), -new);
3076           decisionmap[-new] = -1;
3077           new = 0;
3078           n = 0;        /* redo all rules */
3079         }
3080     }
3081 }
3082
3083 static inline void
3084 undo_removedisabledconflicts(Solver *solv, Queue *removed)
3085 {
3086   int i;
3087   for (i = 0; i < removed->count; i += 2)
3088     solv->decisionmap[removed->elements[i]] = removed->elements[i + 1];
3089 }
3090
3091
3092 /*-------------------------------------------------------------------
3093  *
3094  * weaken solvable dependencies
3095  */
3096
3097 static void
3098 weaken_solvable_deps(Solver *solv, Id p)
3099 {
3100   int i;
3101   Rule *r;
3102
3103   for (i = 1, r = solv->rules + i; i < solv->pkgrules_end; i++, r++)
3104     {
3105       if (r->p != -p)
3106         continue;
3107       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
3108         continue;       /* conflict */
3109       queue_push(&solv->weakruleq, i);
3110     }
3111 }
3112
3113
3114 /********************************************************************/
3115 /* main() */
3116
3117
3118 void
3119 solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap)
3120 {
3121   int i;
3122   Id how, what, select;
3123   Id p, pp;
3124   for (i = 0; i < job->count; i += 2)
3125     {
3126       how = job->elements[i];
3127       if ((how & SOLVER_JOBMASK) != SOLVER_MULTIVERSION)
3128         continue;
3129       what = job->elements[i + 1];
3130       select = how & SOLVER_SELECTMASK;
3131       if (!multiversionmap->size)
3132         map_grow(multiversionmap, pool->nsolvables);
3133       if (select == SOLVER_SOLVABLE_ALL)
3134         {
3135           FOR_POOL_SOLVABLES(p)
3136             MAPSET(multiversionmap, p);
3137         }
3138       else if (select == SOLVER_SOLVABLE_REPO)
3139         {
3140           Solvable *s;
3141           Repo *repo = pool_id2repo(pool, what);
3142           if (repo)
3143             FOR_REPO_SOLVABLES(repo, p, s)
3144               MAPSET(multiversionmap, p);
3145         }
3146       FOR_JOB_SELECT(p, pp, select, what)
3147         MAPSET(multiversionmap, p);
3148     }
3149 }
3150
3151 void
3152 solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap)
3153 {
3154   solver_calculate_multiversionmap(pool, job, multiversionmap);
3155 }
3156
3157 /*
3158  * add a rule created by a job, record job number and weak flag
3159  */
3160 static inline void
3161 solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
3162 {
3163   solver_addrule(solv, p, d);
3164   queue_push(&solv->ruletojob, job);
3165   if (weak)
3166     queue_push(&solv->weakruleq, solv->nrules - 1);
3167 }
3168
3169 static inline void
3170 add_cleandeps_package(Solver *solv, Id p)
3171 {
3172   if (!solv->cleandeps_updatepkgs)
3173     {
3174       solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
3175       queue_init(solv->cleandeps_updatepkgs);
3176     }
3177   queue_pushunique(solv->cleandeps_updatepkgs, p);
3178 }
3179
3180 static void
3181 add_update_target(Solver *solv, Id p, Id how)
3182 {
3183   Pool *pool = solv->pool;
3184   Solvable *s = pool->solvables + p;
3185   Repo *installed = solv->installed;
3186   Id pi, pip;
3187   if (!solv->update_targets)
3188     {
3189       solv->update_targets = solv_calloc(1, sizeof(Queue));
3190       queue_init(solv->update_targets);
3191     }
3192   if (s->repo == installed)
3193     {
3194       queue_push2(solv->update_targets, p, p);
3195       return;
3196     }
3197   FOR_PROVIDES(pi, pip, s->name)
3198     {
3199       Solvable *si = pool->solvables + pi;
3200       if (si->repo != installed || si->name != s->name)
3201         continue;
3202       if (how & SOLVER_FORCEBEST)
3203         {
3204           if (!solv->bestupdatemap.size)
3205             map_grow(&solv->bestupdatemap, installed->end - installed->start);
3206           MAPSET(&solv->bestupdatemap, pi - installed->start);
3207         }
3208       if (how & SOLVER_CLEANDEPS)
3209         add_cleandeps_package(solv, pi);
3210       queue_push2(solv->update_targets, pi, p);
3211       /* check if it's ok to keep the installed package */
3212       if (s->evr == si->evr && solvable_identical(s, si))
3213         queue_push2(solv->update_targets, pi, pi);
3214     }
3215   if (s->obsoletes)
3216     {
3217       Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
3218       while ((obs = *obsp++) != 0)
3219         {
3220           FOR_PROVIDES(pi, pip, obs)
3221             {
3222               Solvable *si = pool->solvables + pi;
3223               if (si->repo != installed)
3224                 continue;
3225               if (si->name == s->name)
3226                 continue;       /* already handled above */
3227               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
3228                 continue;
3229               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
3230                 continue;
3231               if (how & SOLVER_FORCEBEST)
3232                 {
3233                   if (!solv->bestupdatemap.size)
3234                     map_grow(&solv->bestupdatemap, installed->end - installed->start);
3235                   MAPSET(&solv->bestupdatemap, pi - installed->start);
3236                 }
3237               if (how & SOLVER_CLEANDEPS)
3238                 add_cleandeps_package(solv, pi);
3239               queue_push2(solv->update_targets, pi, p);
3240             }
3241         }
3242     }
3243 }
3244
3245 static int
3246 transform_update_targets_sortfn(const void *ap, const void *bp, void *dp)
3247 {
3248   const Id *a = ap;
3249   const Id *b = bp;
3250   if (a[0] - b[0])
3251     return a[0] - b[0];
3252   return a[1] - b[1];
3253 }
3254
3255 static void
3256 transform_update_targets(Solver *solv)
3257 {
3258   Repo *installed = solv->installed;
3259   Queue *update_targets = solv->update_targets;
3260   int i, j;
3261   Id p, q, lastp, lastq;
3262
3263   if (!update_targets->count)
3264     {
3265       queue_free(update_targets);
3266       solv->update_targets = solv_free(update_targets);
3267       return;
3268     }
3269   if (update_targets->count > 2)
3270     solv_sort(update_targets->elements, update_targets->count >> 1, 2 * sizeof(Id), transform_update_targets_sortfn, solv);
3271   queue_insertn(update_targets, 0, installed->end - installed->start, 0);
3272   lastp = lastq = 0;
3273   for (i = j = installed->end - installed->start; i < update_targets->count; i += 2)
3274     {
3275       if ((p = update_targets->elements[i]) != lastp)
3276         {
3277           if (!solv->updatemap.size)
3278             map_grow(&solv->updatemap, installed->end - installed->start);
3279           MAPSET(&solv->updatemap, p - installed->start);
3280           update_targets->elements[j++] = 0;                    /* finish old set */
3281           update_targets->elements[p - installed->start] = j;   /* start new set */
3282           lastp = p;
3283           lastq = 0;
3284         }
3285       if ((q = update_targets->elements[i + 1]) != lastq)
3286         {
3287           update_targets->elements[j++] = q;
3288           lastq = q;
3289         }
3290     }
3291   queue_truncate(update_targets, j);
3292   queue_push(update_targets, 0);        /* finish last set */
3293 }
3294
3295
3296 static void
3297 addedmap2deduceq(Solver *solv, Map *addedmap)
3298 {
3299   Pool *pool = solv->pool;
3300   int i, j;
3301   Id p;
3302   Rule *r;
3303
3304   queue_empty(&solv->addedmap_deduceq);
3305   for (i = 2, j = solv->pkgrules_end - 1; i < pool->nsolvables && j > 0; j--)
3306     {
3307       r = solv->rules + j;
3308       if (r->p >= 0)
3309         continue;
3310       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
3311         continue;
3312       p = -r->p;
3313       if (!MAPTST(addedmap, p))
3314         {
3315           /* should never happen, but... */
3316           if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p)
3317             queue_push(&solv->addedmap_deduceq, -p);
3318           continue;
3319         }
3320       for (; i < p; i++)
3321         if (MAPTST(addedmap, i))
3322           queue_push(&solv->addedmap_deduceq, i);
3323       if (i == p)
3324         i++;
3325     }
3326   for (; i < pool->nsolvables; i++)
3327     if (MAPTST(addedmap, i))
3328       queue_push(&solv->addedmap_deduceq, i);
3329   j = 0;
3330   for (i = 2; i < pool->nsolvables; i++)
3331     if (MAPTST(addedmap, i))
3332       j++;
3333 }
3334
3335 static void
3336 deduceq2addedmap(Solver *solv, Map *addedmap)
3337 {
3338   int j;
3339   Id p;
3340   Rule *r;
3341   for (j = solv->pkgrules_end - 1; j > 0; j--)
3342     {
3343       r = solv->rules + j;
3344       if (r->d < 0 && r->p)
3345         solver_enablerule(solv, r);
3346       if (r->p >= 0)
3347         continue;
3348       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
3349         continue;
3350       p = -r->p;
3351       MAPSET(addedmap, p);
3352     }
3353   for (j = 0; j < solv->addedmap_deduceq.count; j++)
3354     {
3355       p = solv->addedmap_deduceq.elements[j];
3356       if (p > 0)
3357         MAPSET(addedmap, p);
3358       else
3359         MAPCLR(addedmap, p);
3360     }
3361 }
3362
3363
3364 /*
3365  *
3366  * solve job queue
3367  *
3368  */
3369
3370 int
3371 solver_solve(Solver *solv, Queue *job)
3372 {
3373   Pool *pool = solv->pool;
3374   Repo *installed = solv->installed;
3375   int i;
3376   int oldnrules, initialnrules;
3377   Map addedmap;                /* '1' == have pkg-rules for solvable */
3378   Map installcandidatemap;
3379   Id how, what, select, name, weak, p, pp, d;
3380   Queue q;
3381   Solvable *s;
3382   Rule *r;
3383   int now, solve_start;
3384   int hasdupjob = 0;
3385   int hasbestinstalljob = 0;
3386
3387   solve_start = solv_timems(0);
3388
3389   /* log solver options */
3390   POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
3391   POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
3392   POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
3393   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
3394   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors);
3395   POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended);
3396
3397   /* create whatprovides if not already there */
3398   if (!pool->whatprovides)
3399     pool_createwhatprovides(pool);
3400
3401   /* create obsolete index */
3402   policy_create_obsolete_index(solv);
3403
3404   /* remember job */
3405   queue_free(&solv->job);
3406   queue_init_clone(&solv->job, job);
3407   solv->pooljobcnt = pool->pooljobs.count;
3408   if (pool->pooljobs.count)
3409     queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements);
3410   job = &solv->job;
3411
3412   /* free old stuff in jase we re-run a solver */
3413   queuep_free(&solv->update_targets);
3414   queuep_free(&solv->cleandeps_updatepkgs);
3415   queue_empty(&solv->ruleassertions);
3416   solv->bestrules_pkg = solv_free(solv->bestrules_pkg);
3417   solv->yumobsrules_info = solv_free(solv->yumobsrules_info);
3418   solv->choicerules_ref = solv_free(solv->choicerules_ref);
3419   if (solv->noupdate.size)
3420     map_empty(&solv->noupdate);
3421   map_zerosize(&solv->multiversion);
3422   solv->updatemap_all = 0;
3423   map_zerosize(&solv->updatemap);
3424   solv->bestupdatemap_all = 0;
3425   map_zerosize(&solv->bestupdatemap);
3426   solv->fixmap_all = 0;
3427   map_zerosize(&solv->fixmap);
3428   solv->dupmap_all = 0;
3429   map_zerosize(&solv->dupmap);
3430   map_zerosize(&solv->dupinvolvedmap);
3431   solv->droporphanedmap_all = 0;
3432   map_zerosize(&solv->droporphanedmap);
3433   map_zerosize(&solv->cleandepsmap);
3434   map_zerosize(&solv->weakrulemap);
3435   queue_empty(&solv->weakruleq);
3436   solv->watches = solv_free(solv->watches);
3437   queue_empty(&solv->ruletojob);
3438   if (solv->decisionq.count)
3439     memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
3440   queue_empty(&solv->decisionq);
3441   queue_empty(&solv->decisionq_why);
3442   solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
3443   queue_empty(&solv->learnt_why);
3444   queue_empty(&solv->learnt_pool);
3445   queue_empty(&solv->branches);
3446   solv->propagate_index = 0;
3447   queue_empty(&solv->problems);
3448   queue_empty(&solv->solutions);
3449   queue_empty(&solv->orphaned);
3450   solv->stats_learned = solv->stats_unsolvable = 0;
3451   if (solv->recommends_index)
3452     {
3453       map_empty(&solv->recommendsmap);
3454       map_empty(&solv->suggestsmap);
3455       queuep_free(&solv->recommendscplxq);
3456       queuep_free(&solv->suggestscplxq);
3457       solv->recommends_index = 0;
3458     }
3459   queuep_free(&solv->brokenorphanrules);
3460   solv->specialupdaters = solv_free(solv->specialupdaters);
3461
3462
3463   /*
3464    * create basic rule set of all involved packages
3465    * use addedmap bitmap to make sure we don't create rules twice
3466    */
3467
3468   /* create multiversion map if needed */
3469   solver_calculate_multiversionmap(pool, job, &solv->multiversion);
3470
3471   map_init(&addedmap, pool->nsolvables);
3472   MAPSET(&addedmap, SYSTEMSOLVABLE);
3473
3474   map_init(&installcandidatemap, pool->nsolvables);
3475   queue_init(&q);
3476
3477   now = solv_timems(0);
3478   /*
3479    * create rules for all package that could be involved with the solving
3480    * so called: pkg rules
3481    *
3482    */
3483   initialnrules = solv->pkgrules_end ? solv->pkgrules_end : 1;
3484   if (initialnrules > 1)
3485     deduceq2addedmap(solv, &addedmap);
3486   if (solv->nrules != initialnrules)
3487     solver_shrinkrules(solv, initialnrules);
3488   solv->nrules = initialnrules;
3489   solv->pkgrules_end = 0;
3490
3491   if (installed)
3492     {
3493       /* check for update/verify jobs as they need to be known early */
3494       /* also setup the droporphaned map, we need it when creating update rules */
3495       for (i = 0; i < job->count; i += 2)
3496         {
3497           how = job->elements[i];
3498           what = job->elements[i + 1];
3499           select = how & SOLVER_SELECTMASK;
3500           switch (how & SOLVER_JOBMASK)
3501             {
3502             case SOLVER_VERIFY:
3503               if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3504                 solv->fixmap_all = 1;
3505               FOR_JOB_SELECT(p, pp, select, what)
3506                 {
3507                   s = pool->solvables + p;
3508                   if (s->repo != installed)
3509                     continue;
3510                   if (!solv->fixmap.size)
3511                     map_grow(&solv->fixmap, installed->end - installed->start);
3512                   MAPSET(&solv->fixmap, p - installed->start);
3513                 }
3514               break;
3515             case SOLVER_UPDATE:
3516               if (select == SOLVER_SOLVABLE_ALL)
3517                 {
3518                   solv->updatemap_all = 1;
3519                   if (how & SOLVER_FORCEBEST)
3520                     solv->bestupdatemap_all = 1;
3521                   if (how & SOLVER_CLEANDEPS)
3522                     {
3523                       FOR_REPO_SOLVABLES(installed, p, s)
3524                         add_cleandeps_package(solv, p);
3525                     }
3526                 }
3527               else if (select == SOLVER_SOLVABLE_REPO)
3528                 {
3529                   Repo *repo = pool_id2repo(pool, what);
3530                   if (!repo)
3531                     break;
3532                   if (repo == installed && !(how & SOLVER_TARGETED))
3533                     {
3534                       solv->updatemap_all = 1;
3535                       if (how & SOLVER_FORCEBEST)
3536                         solv->bestupdatemap_all = 1;
3537                       if (how & SOLVER_CLEANDEPS)
3538                         {
3539                           FOR_REPO_SOLVABLES(installed, p, s)
3540                             add_cleandeps_package(solv, p);
3541                         }
3542                       break;
3543                     }
3544                   if (solv->noautotarget && !(how & SOLVER_TARGETED))
3545                     break;
3546                   /* targeted update */
3547                   FOR_REPO_SOLVABLES(repo, p, s)
3548                     add_update_target(solv, p, how);
3549                 }
3550               else
3551                 {
3552                   if (!(how & SOLVER_TARGETED))
3553                     {
3554                       int targeted = 1;
3555                       FOR_JOB_SELECT(p, pp, select, what)
3556                         {
3557                           s = pool->solvables + p;
3558                           if (s->repo != installed)
3559                             continue;
3560                           if (!solv->updatemap.size)
3561                             map_grow(&solv->updatemap, installed->end - installed->start);
3562                           MAPSET(&solv->updatemap, p - installed->start);
3563                           if (how & SOLVER_FORCEBEST)
3564                             {
3565                               if (!solv->bestupdatemap.size)
3566                                 map_grow(&solv->bestupdatemap, installed->end - installed->start);
3567                               MAPSET(&solv->bestupdatemap, p - installed->start);
3568                             }
3569                           if (how & SOLVER_CLEANDEPS)
3570                             add_cleandeps_package(solv, p);
3571                           targeted = 0;
3572                         }
3573                       if (!targeted || solv->noautotarget)
3574                         break;
3575                     }
3576                   FOR_JOB_SELECT(p, pp, select, what)
3577                     add_update_target(solv, p, how);
3578                 }
3579               break;
3580             case SOLVER_DROP_ORPHANED:
3581               if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
3582                 solv->droporphanedmap_all = 1;
3583               FOR_JOB_SELECT(p, pp, select, what)
3584                 {
3585                   s = pool->solvables + p;
3586                   if (s->repo != installed)
3587                     continue;
3588                   if (!solv->droporphanedmap.size)
3589                     map_grow(&solv->droporphanedmap, installed->end - installed->start);
3590                   MAPSET(&solv->droporphanedmap, p - installed->start);
3591                 }
3592               break;
3593             default:
3594               break;
3595             }
3596         }
3597
3598       if (solv->update_targets)
3599         transform_update_targets(solv);
3600
3601       oldnrules = solv->nrules;
3602       FOR_REPO_SOLVABLES(installed, p, s)
3603         solver_addpkgrulesforsolvable(solv, s, &addedmap);
3604       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for installed solvables\n", solv->nrules - oldnrules);
3605       oldnrules = solv->nrules;
3606       FOR_REPO_SOLVABLES(installed, p, s)
3607         solver_addpkgrulesforupdaters(solv, s, &addedmap, 1);
3608       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for updaters of installed solvables\n", solv->nrules - oldnrules);
3609     }
3610
3611   /*
3612    * create rules for all packages involved in the job
3613    * (to be installed or removed)
3614    */
3615
3616   oldnrules = solv->nrules;
3617   for (i = 0; i < job->count; i += 2)
3618     {
3619       how = job->elements[i];
3620       what = job->elements[i + 1];
3621       select = how & SOLVER_SELECTMASK;
3622
3623       switch (how & SOLVER_JOBMASK)
3624         {
3625         case SOLVER_INSTALL:
3626           FOR_JOB_SELECT(p, pp, select, what)
3627             {
3628               MAPSET(&installcandidatemap, p);
3629               solver_addpkgrulesforsolvable(solv, pool->solvables + p, &addedmap);
3630             }
3631           break;
3632         case SOLVER_DISTUPGRADE:
3633           if (select == SOLVER_SOLVABLE_ALL)
3634             {
3635               solv->dupmap_all = 1;
3636               solv->updatemap_all = 1;
3637               if (how & SOLVER_FORCEBEST)
3638                 solv->bestupdatemap_all = 1;
3639             }
3640           if (!solv->dupmap_all)
3641             hasdupjob = 1;
3642           break;
3643         default:
3644           break;
3645         }
3646     }
3647   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for packages involved in a job\n", solv->nrules - oldnrules);
3648
3649
3650   /*
3651    * add rules for suggests, enhances
3652    */
3653   oldnrules = solv->nrules;
3654   if (hasdupjob && !solv->updatemap_all && solv->dosplitprovides && solv->installed)
3655     solver_addpkgrulesforweak(solv, &addedmap);
3656   else
3657     solver_addpkgrulesforweak(solv, &addedmap);
3658   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules because of weak dependencies\n", solv->nrules - oldnrules);
3659
3660 #ifdef ENABLE_LINKED_PKGS
3661   oldnrules = solv->nrules;
3662   solver_addpkgrulesforlinked(solv, &addedmap);
3663   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules because of linked packages\n", solv->nrules - oldnrules);
3664 #endif
3665
3666   /*
3667    * first pass done, we now have all the pkg rules we need.
3668    * unify existing rules before going over all job rules and
3669    * policy rules.
3670    * at this point the system is always solvable,
3671    * as an empty system (remove all packages) is a valid solution
3672    */
3673
3674   IF_POOLDEBUG (SOLV_DEBUG_STATS)
3675     {
3676       int possible = 0, installable = 0;
3677       for (i = 1; i < pool->nsolvables; i++)
3678         {
3679           if (pool_installable(pool, pool->solvables + i))
3680             installable++;
3681           if (MAPTST(&addedmap, i))
3682             possible++;
3683         }
3684       POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
3685     }
3686
3687   if (solv->nrules > initialnrules)
3688     solver_unifyrules(solv);                    /* remove duplicate pkg rules */
3689   solv->pkgrules_end = solv->nrules;            /* mark end of pkg rules */
3690
3691   if (solv->nrules > initialnrules)
3692     addedmap2deduceq(solv, &addedmap);          /* so that we can recreate the addedmap */
3693
3694   POOL_DEBUG(SOLV_DEBUG_STATS, "pkg rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3695   POOL_DEBUG(SOLV_DEBUG_STATS, "pkg rule creation took %d ms\n", solv_timems(now));
3696
3697   /* create dup maps if needed. We need the maps early to create our
3698    * update rules */
3699   if (hasdupjob)
3700     solver_createdupmaps(solv);
3701
3702   /*
3703    * create feature rules
3704    *
3705    * foreach installed:
3706    *   create assertion (keep installed, if no update available)
3707    *   or
3708    *   create update rule (A|update1(A)|update2(A)|...)
3709    *
3710    * those are used later on to keep a version of the installed packages in
3711    * best effort mode
3712    */
3713
3714   solv->featurerules = solv->nrules;              /* mark start of feature rules */
3715   if (installed)
3716     {
3717       /* foreach possibly installed solvable */
3718       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3719         {
3720           if (s->repo != installed)
3721             {
3722               solver_addrule(solv, 0, 0);       /* create dummy rule */
3723               continue;
3724             }
3725           solver_addupdaterule(solv, s, 1);    /* allow s to be updated */
3726         }
3727       /* make sure we accounted for all rules */
3728       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
3729     }
3730   solv->featurerules_end = solv->nrules;
3731
3732     /*
3733      * Add update rules for installed solvables
3734      *
3735      * almost identical to feature rules
3736      * except that downgrades/archchanges/vendorchanges are not allowed
3737      */
3738
3739   solv->updaterules = solv->nrules;
3740
3741   if (installed)
3742     { /* foreach installed solvables */
3743       /* we create all update rules, but disable some later on depending on the job */
3744       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3745         {
3746           Rule *sr;
3747
3748           if (s->repo != installed)
3749             {
3750               solver_addrule(solv, 0, 0);       /* create dummy rule */
3751               continue;
3752             }
3753           solver_addupdaterule(solv, s, 0);     /* allowall = 0: downgrades not allowed */
3754           /*
3755            * check for and remove duplicate
3756            */
3757           r = solv->rules + solv->nrules - 1;           /* r: update rule */
3758           if (!r->p)
3759             continue;
3760           sr = r - (installed->end - installed->start); /* sr: feature rule */
3761           /* it's also orphaned if the feature rule consists just of the installed package */
3762           if (!solv->dupmap_all && sr->p == i && !sr->d && !sr->w2)
3763             queue_push(&solv->orphaned, i);
3764           if (!solver_rulecmp(solv, r, sr))
3765             memset(sr, 0, sizeof(*sr));         /* delete unneeded feature rule */
3766           else
3767             solver_disablerule(solv, sr);       /* disable feature rule for now */
3768         }
3769       /* consistency check: we added a rule for _every_ installed solvable */
3770       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
3771     }
3772   solv->updaterules_end = solv->nrules;
3773
3774
3775   /*
3776    * now add all job rules
3777    */
3778
3779   solv->jobrules = solv->nrules;
3780   for (i = 0; i < job->count; i += 2)
3781     {
3782       oldnrules = solv->nrules;
3783
3784       if (i && i == solv->pooljobcnt)
3785         POOL_DEBUG(SOLV_DEBUG_JOB, "end of pool jobs\n");
3786       how = job->elements[i];
3787       what = job->elements[i + 1];
3788       weak = how & SOLVER_WEAK;
3789       select = how & SOLVER_SELECTMASK;
3790       switch (how & SOLVER_JOBMASK)
3791         {
3792         case SOLVER_INSTALL:
3793           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3794           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3795             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3796           if (select == SOLVER_SOLVABLE)
3797             {
3798               p = what;
3799               d = 0;
3800             }
3801           else
3802             {
3803               queue_empty(&q);
3804               FOR_JOB_SELECT(p, pp, select, what)
3805                 queue_push(&q, p);
3806               if (!q.count)
3807                 {
3808                   if (select == SOLVER_SOLVABLE_ONE_OF)
3809                     break;      /* ignore empty installs */
3810                   /* no candidate found or unsupported, make this an impossible rule */
3811                   queue_push(&q, -SYSTEMSOLVABLE);
3812                 }
3813               p = queue_shift(&q);      /* get first candidate */
3814               d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
3815             }
3816           /* force install of namespace supplements hack */
3817           if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what))
3818             {
3819               Reldep *rd = GETRELDEP(pool, what);
3820               if (rd->flags == REL_NAMESPACE)
3821                 {
3822                   p = SYSTEMSOLVABLE;
3823                   if (!solv->installsuppdepq)
3824                     {
3825                       solv->installsuppdepq = solv_calloc(1, sizeof(Queue));
3826                       queue_init(solv->installsuppdepq);
3827                     }
3828                   queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
3829                 }
3830             }
3831           solver_addjobrule(solv, p, d, i, weak);
3832           if (how & SOLVER_FORCEBEST)
3833             hasbestinstalljob = 1;
3834           break;
3835         case SOLVER_ERASE:
3836           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
3837           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3838             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3839           /* specific solvable: by id or by nevra */
3840           name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
3841           if (select == SOLVER_SOLVABLE_ALL)    /* hmmm ;) */
3842             {
3843               FOR_POOL_SOLVABLES(p)
3844                 solver_addjobrule(solv, -p, 0, i, weak);
3845             }
3846           else if (select == SOLVER_SOLVABLE_REPO)
3847             {
3848               Repo *repo = pool_id2repo(pool, what);
3849               if (repo)
3850                 FOR_REPO_SOLVABLES(repo, p, s)
3851                   solver_addjobrule(solv, -p, 0, i, weak);
3852             }
3853           FOR_JOB_SELECT(p, pp, select, what)
3854             {
3855               s = pool->solvables + p;
3856               if (installed && s->repo == installed)
3857                 name = !name ? s->name : -1;
3858               solver_addjobrule(solv, -p, 0, i, weak);
3859             }
3860           /* special case for "erase a specific solvable": we also
3861            * erase all other solvables with that name, so that they
3862            * don't get picked up as replacement.
3863            * name is > 0 if exactly one installed solvable matched.
3864            */
3865           /* XXX: look also at packages that obsolete this package? */
3866           if (name > 0)
3867             {
3868               int j, k;
3869               k = solv->nrules;
3870               FOR_PROVIDES(p, pp, name)
3871                 {
3872                   s = pool->solvables + p;
3873                   if (s->name != name)
3874                     continue;
3875                   /* keep other versions installed */
3876                   if (s->repo == installed)
3877                     continue;
3878                   /* keep installcandidates of other jobs */
3879                   if (MAPTST(&installcandidatemap, p))
3880                     continue;
3881                   /* don't add the same rule twice */
3882                   for (j = oldnrules; j < k; j++)
3883                     if (solv->rules[j].p == -p)
3884                       break;
3885                   if (j == k)
3886                     solver_addjobrule(solv, -p, 0, i, weak);    /* remove by id */
3887                 }
3888             }
3889           break;
3890
3891         case SOLVER_UPDATE:
3892           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3893           break;
3894         case SOLVER_VERIFY:
3895           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3896           break;
3897         case SOLVER_WEAKENDEPS:
3898           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3899           if (select != SOLVER_SOLVABLE)
3900             break;
3901           s = pool->solvables + what;
3902           weaken_solvable_deps(solv, what);
3903           break;
3904         case SOLVER_MULTIVERSION:
3905           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %smultiversion %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3906           break;
3907         case SOLVER_LOCK:
3908           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3909           if (select == SOLVER_SOLVABLE_ALL)
3910             {
3911               FOR_POOL_SOLVABLES(p)
3912                 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3913             }
3914           else if (select == SOLVER_SOLVABLE_REPO)
3915             {
3916               Repo *repo = pool_id2repo(pool, what);
3917               if (repo)
3918                 FOR_REPO_SOLVABLES(repo, p, s)
3919                   solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3920             }
3921           FOR_JOB_SELECT(p, pp, select, what)
3922             solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3923           break;
3924         case SOLVER_DISTUPGRADE:
3925           POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
3926           break;
3927         case SOLVER_DROP_ORPHANED:
3928           POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
3929           break;
3930         case SOLVER_USERINSTALLED:
3931           POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
3932           break;
3933         default:
3934           POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
3935           break;
3936         }
3937         
3938       IF_POOLDEBUG (SOLV_DEBUG_JOB)
3939         {
3940           int j;
3941           if (solv->nrules == oldnrules)
3942             POOL_DEBUG(SOLV_DEBUG_JOB, "  - no rule created\n");
3943           for (j = oldnrules; j < solv->nrules; j++)
3944             {
3945               POOL_DEBUG(SOLV_DEBUG_JOB, "  - job ");
3946               solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j);
3947             }
3948         }
3949     }
3950   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
3951   solv->jobrules_end = solv->nrules;
3952
3953   /* now create infarch and dup rules */
3954   if (!solv->noinfarchcheck)
3955     {
3956       solver_addinfarchrules(solv, &addedmap);
3957 #if 0
3958       if (pool->implicitobsoleteusescolors)
3959         {
3960           /* currently doesn't work well with infarch rules, so make
3961            * them weak */
3962           for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
3963             queue_push(&solv->weakruleq, i);
3964         }
3965 #endif
3966     }
3967   else
3968     solv->infarchrules = solv->infarchrules_end = solv->nrules;
3969
3970   if (hasdupjob)
3971     solver_addduprules(solv, &addedmap);
3972   else
3973     solv->duprules = solv->duprules_end = solv->nrules;
3974
3975   if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
3976     solver_addbestrules(solv, hasbestinstalljob);
3977   else
3978     solv->bestrules = solv->bestrules_end = solv->nrules;
3979
3980   if (hasdupjob)
3981     solver_freedupmaps(solv);   /* no longer needed */
3982
3983   if (solv->do_yum_obsoletes)
3984     solver_addyumobsrules(solv);
3985   else
3986     solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
3987
3988   if (1)
3989     solver_addchoicerules(solv);
3990   else
3991     solv->choicerules = solv->choicerules_end = solv->nrules;
3992
3993   if (0)
3994     {
3995       for (i = solv->featurerules; i < solv->nrules; i++)
3996         solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
3997     }
3998   /* all rules created
3999    * --------------------------------------------------------------
4000    * prepare for solving
4001    */
4002
4003   /* free unneeded memory */
4004   map_free(&addedmap);
4005   map_free(&installcandidatemap);
4006   queue_free(&q);
4007
4008   POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules);
4009   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
4010
4011   /* create weak map */
4012   map_init(&solv->weakrulemap, solv->nrules);
4013   for (i = 0; i < solv->weakruleq.count; i++)
4014     {
4015       p = solv->weakruleq.elements[i];
4016       MAPSET(&solv->weakrulemap, p);
4017     }
4018
4019   /* enable cleandepsmap creation if we have updatepkgs */
4020   if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size)
4021     map_grow(&solv->cleandepsmap, installed->end - installed->start);
4022   /* no mistakes */
4023   if (solv->cleandeps_mistakes)
4024     {
4025       queue_free(solv->cleandeps_mistakes);
4026       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
4027     }
4028
4029   /* all new rules are learnt after this point */
4030   solv->learntrules = solv->nrules;
4031
4032   /* create watches chains */
4033   makewatches(solv);
4034
4035   /* create assertion index. it is only used to speed up
4036    * makeruledecsions() a bit */
4037   for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
4038     if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
4039       queue_push(&solv->ruleassertions, i);
4040
4041   /* disable update rules that conflict with our job */
4042   solver_disablepolicyrules(solv);
4043
4044   /* break orphans if requested */
4045   if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans)
4046     solver_breakorphans(solv);
4047
4048   /* make initial decisions based on assertion rules */
4049   makeruledecisions(solv);
4050   POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count);
4051
4052   /*
4053    * ********************************************
4054    * solve!
4055    * ********************************************
4056    */
4057
4058   now = solv_timems(0);
4059   solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
4060   POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now));
4061
4062   /*
4063    * prepare solution queue if there were problems
4064    */
4065   solver_prepare_solutions(solv);
4066
4067   POOL_DEBUG(SOLV_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
4068   POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start));
4069
4070   /* return number of problems */
4071   return solv->problems.count ? solv->problems.count / 2 : 0;
4072 }
4073
4074 Transaction *
4075 solver_create_transaction(Solver *solv)
4076 {
4077   return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->multiversion);
4078 }
4079
4080 void solver_get_orphaned(Solver *solv, Queue *orphanedq)
4081 {
4082   queue_free(orphanedq);
4083   queue_init_clone(orphanedq, &solv->orphaned);
4084 }
4085
4086 void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
4087 {
4088   Pool *pool = solv->pool;
4089   Queue redoq, disabledq;
4090   int goterase, i;
4091   Solvable *s;
4092   Rule *r;
4093   Map obsmap;
4094
4095   if (!recommendationsq && !suggestionsq)
4096     return;
4097
4098   map_init(&obsmap, pool->nsolvables);
4099   if (solv->installed)
4100     {
4101       Id obs, *obsp, p, po, ppo;
4102       for (p = solv->installed->start; p < solv->installed->end; p++)
4103         {
4104           s = pool->solvables + p;
4105           if (s->repo != solv->installed || !s->obsoletes)
4106             continue;
4107           if (solv->decisionmap[p] <= 0)
4108             continue;
4109           if (solv->multiversion.size && MAPTST(&solv->multiversion, p))
4110             continue;
4111           obsp = s->repo->idarraydata + s->obsoletes;
4112           /* foreach obsoletes */
4113           while ((obs = *obsp++) != 0)
4114             FOR_PROVIDES(po, ppo, obs)
4115               MAPSET(&obsmap, po);
4116         }
4117     }
4118
4119   queue_init(&redoq);
4120   queue_init(&disabledq);
4121   goterase = 0;
4122   /* disable all erase jobs (including weak "keep uninstalled" rules) */
4123   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
4124     {
4125       if (r->d < 0)     /* disabled ? */
4126         continue;
4127       if (r->p >= 0)    /* install job? */
4128         continue;
4129       queue_push(&disabledq, i);
4130       solver_disablerule(solv, r);
4131       goterase++;
4132     }
4133
4134   if (goterase)
4135     {
4136       enabledisablelearntrules(solv);
4137       removedisabledconflicts(solv, &redoq);
4138     }
4139
4140   /*
4141    * find recommended packages
4142    */
4143   if (recommendationsq)
4144     {
4145       Id rec, *recp, p, pp;
4146
4147       queue_empty(recommendationsq);
4148       /* create map of all recommened packages */
4149       solv->recommends_index = -1;
4150       MAPZERO(&solv->recommendsmap);
4151
4152       /* put all packages the solver already chose in the map */
4153       if (solv->decisioncnt_weak)
4154         {
4155           for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++)
4156             {
4157               Id why;
4158               why = solv->decisionq_why.elements[i];
4159               if (why)
4160                 continue;       /* forced by unit rule or dep resolving */
4161               p = solv->decisionq.elements[i];
4162               if (p < 0)
4163                 continue;
4164               MAPSET(&solv->recommendsmap, p);
4165             }
4166         }
4167
4168       for (i = 0; i < solv->decisionq.count; i++)
4169         {
4170           p = solv->decisionq.elements[i];
4171           if (p < 0)
4172             continue;
4173           s = pool->solvables + p;
4174           if (s->recommends)
4175             {
4176               recp = s->repo->idarraydata + s->recommends;
4177               while ((rec = *recp++) != 0)
4178                 {
4179 #ifdef ENABLE_COMPLEX_DEPS
4180                   if (pool_is_complex_dep(pool, rec))
4181                     {
4182                       do_complex_recommendations(solv, rec, &solv->recommendsmap, noselected);
4183                       continue;
4184                     }
4185 #endif
4186                   FOR_PROVIDES(p, pp, rec)
4187                     if (solv->decisionmap[p] > 0)
4188                       break;
4189                   if (p)
4190                     {
4191                       if (!noselected)
4192                         {
4193                           FOR_PROVIDES(p, pp, rec)
4194                             if (solv->decisionmap[p] > 0)
4195                               MAPSET(&solv->recommendsmap, p);
4196                         }
4197                       continue; /* p != 0: already fulfilled */
4198                     }
4199                   FOR_PROVIDES(p, pp, rec)
4200                     MAPSET(&solv->recommendsmap, p);
4201                 }
4202             }
4203         }
4204       for (i = 1; i < pool->nsolvables; i++)
4205         {
4206           if (solv->decisionmap[i] < 0)
4207             continue;
4208           if (solv->decisionmap[i] > 0 && noselected)
4209             continue;
4210           if (MAPTST(&obsmap, i))
4211             continue;
4212           s = pool->solvables + i;
4213           if (!MAPTST(&solv->recommendsmap, i))
4214             {
4215               if (!s->supplements)
4216                 continue;
4217               if (!pool_installable(pool, s))
4218                 continue;
4219               if (!solver_is_supplementing(solv, s))
4220                 continue;
4221             }
4222           queue_push(recommendationsq, i);
4223         }
4224       /* we use MODE_SUGGEST here so that repo prio is ignored */
4225       policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
4226     }
4227
4228   /*
4229    * find suggested packages
4230    */
4231
4232   if (suggestionsq)
4233     {
4234       Id sug, *sugp, p, pp;
4235
4236       queue_empty(suggestionsq);
4237       /* create map of all suggests that are still open */
4238       solv->recommends_index = -1;
4239       MAPZERO(&solv->suggestsmap);
4240       for (i = 0; i < solv->decisionq.count; i++)
4241         {
4242           p = solv->decisionq.elements[i];
4243           if (p < 0)
4244             continue;
4245           s = pool->solvables + p;
4246           if (s->suggests)
4247             {
4248               sugp = s->repo->idarraydata + s->suggests;
4249               while ((sug = *sugp++) != 0)
4250                 {
4251 #ifdef ENABLE_COMPLEX_DEPS
4252                   if (pool_is_complex_dep(pool, sug))
4253                     {
4254                       do_complex_recommendations(solv, sug, &solv->suggestsmap, noselected);
4255                       continue;
4256                     }
4257 #endif
4258                   FOR_PROVIDES(p, pp, sug)
4259                     if (solv->decisionmap[p] > 0)
4260                       break;
4261                   if (p)
4262                     {
4263                       if (!noselected)
4264                         {
4265                           FOR_PROVIDES(p, pp, sug)
4266                             if (solv->decisionmap[p] > 0)
4267                               MAPSET(&solv->suggestsmap, p);
4268                         }
4269                       continue; /* already fulfilled */
4270                     }
4271                   FOR_PROVIDES(p, pp, sug)
4272                     MAPSET(&solv->suggestsmap, p);
4273                 }
4274             }
4275         }
4276       for (i = 1; i < pool->nsolvables; i++)
4277         {
4278           if (solv->decisionmap[i] < 0)
4279             continue;
4280           if (solv->decisionmap[i] > 0 && noselected)
4281             continue;
4282           if (MAPTST(&obsmap, i))
4283             continue;
4284           s = pool->solvables + i;
4285           if (!MAPTST(&solv->suggestsmap, i))
4286             {
4287               if (!s->enhances)
4288                 continue;
4289               if (!pool_installable(pool, s))
4290                 continue;
4291               if (!solver_is_enhancing(solv, s))
4292                 continue;
4293             }
4294           queue_push(suggestionsq, i);
4295         }
4296       policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
4297     }
4298
4299   /* undo removedisabledconflicts */
4300   if (redoq.count)
4301     undo_removedisabledconflicts(solv, &redoq);
4302   queue_free(&redoq);
4303
4304   /* undo job rule disabling */
4305   for (i = 0; i < disabledq.count; i++)
4306     solver_enablerule(solv, solv->rules + disabledq.elements[i]);
4307   queue_free(&disabledq);
4308   map_free(&obsmap);
4309 }
4310
4311
4312 /***********************************************************************/
4313 /* disk usage computations */
4314
4315 /*-------------------------------------------------------------------
4316  *
4317  * calculate DU changes
4318  */
4319
4320 void
4321 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
4322 {
4323   Map installedmap;
4324
4325   solver_create_state_maps(solv, &installedmap, 0);
4326   pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
4327   map_free(&installedmap);
4328 }
4329
4330
4331 /*-------------------------------------------------------------------
4332  *
4333  * calculate changes in install size
4334  */
4335
4336 int
4337 solver_calc_installsizechange(Solver *solv)
4338 {
4339   Map installedmap;
4340   int change;
4341
4342   solver_create_state_maps(solv, &installedmap, 0);
4343   change = pool_calc_installsizechange(solv->pool, &installedmap);
4344   map_free(&installedmap);
4345   return change;
4346 }
4347
4348 void
4349 solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
4350 {
4351   pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
4352 }
4353
4354 void
4355 solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
4356 {
4357   Pool *pool = solv->pool;
4358   Map installedmap;
4359   int i;
4360   pool_create_state_maps(pool,  &solv->decisionq, &installedmap, 0);
4361   pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0);
4362   for (i = 0; i < res->count; i++)
4363     if (res->elements[i] != -1)
4364       {
4365         Solvable *s = pool->solvables + pkgs->elements[i];
4366         if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap))
4367           res->elements[i] = -1;
4368       }
4369   map_free(&installedmap);
4370 }
4371
4372 /*-------------------------------------------------------------------
4373  *
4374  * decision introspection
4375  */
4376
4377 int
4378 solver_get_decisionlevel(Solver *solv, Id p)
4379 {
4380   return solv->decisionmap[p];
4381 }
4382
4383 void
4384 solver_get_decisionqueue(Solver *solv, Queue *decisionq)
4385 {
4386   queue_free(decisionq);
4387   queue_init_clone(decisionq, &solv->decisionq);
4388 }
4389
4390 int
4391 solver_get_lastdecisionblocklevel(Solver *solv)
4392 {
4393   Id p;
4394   if (solv->decisionq.count == 0)
4395     return 0;
4396   p = solv->decisionq.elements[solv->decisionq.count - 1];
4397   if (p < 0)
4398     p = -p;
4399   return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
4400 }
4401
4402 void
4403 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
4404 {
4405   Id p;
4406   int i;
4407
4408   queue_empty(decisionq);
4409   for (i = 0; i < solv->decisionq.count; i++)
4410     {
4411       p = solv->decisionq.elements[i];
4412       if (p < 0)
4413         p = -p;
4414       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
4415         break;
4416     }
4417   if (i == solv->decisionq.count)
4418     return;
4419   for (i = 0; i < solv->decisionq.count; i++)
4420     {
4421       p = solv->decisionq.elements[i];
4422       if (p < 0)
4423         p = -p;
4424       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
4425         queue_push(decisionq, p);
4426       else
4427         break;
4428     }
4429 }
4430
4431 int
4432 solver_describe_decision(Solver *solv, Id p, Id *infop)
4433 {
4434   int i;
4435   Id pp, why;
4436
4437   if (infop)
4438     *infop = 0;
4439   if (!solv->decisionmap[p])
4440     return SOLVER_REASON_UNRELATED;
4441   pp = solv->decisionmap[p] < 0 ? -p : p;
4442   for (i = 0; i < solv->decisionq.count; i++)
4443     if (solv->decisionq.elements[i] == pp)
4444       break;
4445   if (i == solv->decisionq.count)       /* just in case... */
4446     return SOLVER_REASON_UNRELATED;
4447   why = solv->decisionq_why.elements[i];
4448   if (infop)
4449     *infop = why > 0 ? why : -why;
4450   if (why > 0)
4451     return SOLVER_REASON_UNIT_RULE;
4452   why = -why;
4453   if (i == 0)
4454     return SOLVER_REASON_KEEP_INSTALLED;        /* the systemsolvable */
4455   if (i < solv->decisioncnt_update)
4456     return SOLVER_REASON_RESOLVE_JOB;
4457   if (i < solv->decisioncnt_keep)
4458     {
4459       if (why == 0 && pp < 0)
4460         return SOLVER_REASON_CLEANDEPS_ERASE;
4461       return SOLVER_REASON_UPDATE_INSTALLED;
4462     }
4463   if (i < solv->decisioncnt_resolve)
4464     {
4465       if (solv->focus_installed && i >= solv->decisioncnt_jobs)
4466         return SOLVER_REASON_RESOLVE_JOB;
4467       if (why == 0 && pp < 0)
4468         return SOLVER_REASON_CLEANDEPS_ERASE;
4469       return SOLVER_REASON_KEEP_INSTALLED;
4470     }
4471   if (why > 0)
4472     return SOLVER_REASON_RESOLVE;
4473   /* weak or orphaned */
4474   if (i < solv->decisioncnt_orphan)
4475     return SOLVER_REASON_WEAKDEP;
4476   return SOLVER_REASON_RESOLVE_ORPHAN;
4477 }
4478
4479
4480 void
4481 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
4482 {
4483   Pool *pool = solv->pool;
4484   int i;
4485   int level = solv->decisionmap[p];
4486   int decisionno;
4487   Solvable *s;
4488
4489   queue_empty(whyq);
4490   if (level < 0)
4491     return;     /* huh? */
4492   for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
4493     if (solv->decisionq.elements[decisionno] == p)
4494       break;
4495   if (decisionno == solv->decisionq.count)
4496     return;     /* huh? */
4497   if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
4498     return;     /* huh? */
4499
4500   /* 1) list all packages that recommend us */
4501   for (i = 1; i < pool->nsolvables; i++)
4502     {
4503       Id *recp, rec, pp2, p2;
4504       if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
4505         continue;
4506       s = pool->solvables + i;
4507       if (!s->recommends)
4508         continue;
4509       if (!solv->addalreadyrecommended && s->repo == solv->installed)
4510         continue;
4511       recp = s->repo->idarraydata + s->recommends;
4512       while ((rec = *recp++) != 0)
4513         {
4514           int found = 0;
4515           FOR_PROVIDES(p2, pp2, rec)
4516             {
4517               if (p2 == p)
4518                 found = 1;
4519               else
4520                 {
4521                   /* if p2 is already installed, this recommends is ignored */
4522                   if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
4523                     break;
4524                 }
4525             }
4526           if (!p2 && found)
4527             {
4528               queue_push(whyq, SOLVER_REASON_RECOMMENDED);
4529               queue_push2(whyq, i, rec);
4530             }
4531         }
4532     }
4533   /* 2) list all supplements */
4534   s = pool->solvables + p;
4535   if (s->supplements && level > 0)
4536     {
4537       Id *supp, sup, pp2, p2;
4538       /* this is a hack. to use solver_dep_fulfilled we temporarily clear
4539        * everything above our level in the decisionmap */
4540       for (i = decisionno; i < solv->decisionq.count; i++ )
4541         {
4542           p2 = solv->decisionq.elements[i];
4543           if (p2 > 0)
4544             solv->decisionmap[p2] = -solv->decisionmap[p2];
4545         }
4546       supp = s->repo->idarraydata + s->supplements;
4547       while ((sup = *supp++) != 0)
4548         if (solver_dep_fulfilled(solv, sup))
4549           {
4550             int found = 0;
4551             /* let's see if this is an easy supp */
4552             FOR_PROVIDES(p2, pp2, sup)
4553               {
4554                 if (!solv->addalreadyrecommended && solv->installed)
4555                   {
4556                     if (pool->solvables[p2].repo == solv->installed)
4557                       continue;
4558                   }
4559                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
4560                   {
4561                     queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
4562                     queue_push2(whyq, p2, sup);
4563                     found = 1;
4564                   }
4565               }
4566             if (!found)
4567               {
4568                 /* hard case, just note dependency with no package */
4569                 queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
4570                 queue_push2(whyq, 0, sup);
4571               }
4572           }
4573       for (i = decisionno; i < solv->decisionq.count; i++)
4574         {
4575           p2 = solv->decisionq.elements[i];
4576           if (p2 > 0)
4577             solv->decisionmap[p2] = -solv->decisionmap[p2];
4578         }
4579     }
4580 }
4581
4582 void
4583 pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
4584 {
4585   Id p, pp;
4586   how &= SOLVER_SELECTMASK;
4587   queue_empty(pkgs);
4588   if (how == SOLVER_SOLVABLE_ALL)
4589     {
4590       FOR_POOL_SOLVABLES(p)
4591         queue_push(pkgs, p);
4592     }
4593   else if (how == SOLVER_SOLVABLE_REPO)
4594     {
4595       Repo *repo = pool_id2repo(pool, what);
4596       Solvable *s;
4597       if (repo)
4598         FOR_REPO_SOLVABLES(repo, p, s)
4599           queue_push(pkgs, p);
4600     }
4601   else
4602     {
4603       FOR_JOB_SELECT(p, pp, how, what)
4604         queue_push(pkgs, p);
4605     }
4606 }
4607
4608 int
4609 pool_isemptyupdatejob(Pool *pool, Id how, Id what)
4610 {
4611   Id p, pp, pi, pip;
4612   Id select = how & SOLVER_SELECTMASK;
4613   if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
4614     return 0;
4615   if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
4616     return 0;
4617   if (!pool->installed)
4618     return 1;
4619   FOR_JOB_SELECT(p, pp, select, what)
4620     if (pool->solvables[p].repo == pool->installed)
4621       return 0;
4622   /* hard work */
4623   FOR_JOB_SELECT(p, pp, select, what)
4624     {
4625       Solvable *s = pool->solvables + p;
4626       FOR_PROVIDES(pi, pip, s->name)
4627         {
4628           Solvable *si = pool->solvables + pi;
4629           if (si->repo != pool->installed || si->name != s->name)
4630             continue;
4631           return 0;
4632         }
4633       if (s->obsoletes)
4634         {
4635           Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
4636           while ((obs = *obsp++) != 0)
4637             {
4638               FOR_PROVIDES(pi, pip, obs)
4639                 {
4640                   Solvable *si = pool->solvables + pi;
4641                   if (si->repo != pool->installed)
4642                     continue;
4643                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
4644                     continue;
4645                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
4646                     continue;
4647                   return 0;
4648                 }
4649             }
4650         }
4651     }
4652   return 1;
4653 }
4654
4655 static int
4656 get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
4657 {
4658   return *(Id *)ap - *(Id *)bp;
4659 }
4660
4661 static int
4662 get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
4663 {
4664   Pool *pool = dp;
4665   return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
4666 }
4667
4668 static void
4669 get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
4670 {
4671   Id lastp = -1;
4672   int i, j;
4673   if ((flags & GET_USERINSTALLED_NAMES) != 0)
4674     solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
4675   else
4676     solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
4677   for (i = j = 0; i < q->count; i++)
4678     if (q->elements[i] != lastp)
4679       q->elements[j++] = lastp = q->elements[i];
4680   queue_truncate(q, j);
4681 }
4682
4683 void
4684 solver_get_userinstalled(Solver *solv, Queue *q, int flags)
4685 {
4686   Pool *pool = solv->pool;
4687   Id p, p2, pp;
4688   Solvable *s;
4689   Repo *installed = solv->installed;
4690   int i, j;
4691   Map userinstalled;
4692   
4693   map_init(&userinstalled, 0);
4694   queue_empty(q);
4695   /* first process jobs */
4696   for (i = 0; i < solv->job.count; i += 2)
4697     {
4698       Id how = solv->job.elements[i];
4699       Id what, select;
4700       if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
4701         {
4702           if (!userinstalled.size)
4703             map_grow(&userinstalled, installed->end - installed->start);
4704           what = solv->job.elements[i + 1];
4705           select = how & SOLVER_SELECTMASK;
4706           if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
4707             FOR_REPO_SOLVABLES(installed, p, s)
4708               MAPSET(&userinstalled, p - installed->start);
4709           FOR_JOB_SELECT(p, pp, select, what)
4710             if (pool->solvables[p].repo == installed)
4711               MAPSET(&userinstalled, p - installed->start);
4712           continue;
4713         }
4714       if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
4715         continue;
4716       if ((how & SOLVER_NOTBYUSER) != 0)
4717         continue;
4718       what = solv->job.elements[i + 1];
4719       select = how & SOLVER_SELECTMASK;
4720       FOR_JOB_SELECT(p, pp, select, what)
4721         if (solv->decisionmap[p] > 0)
4722           {
4723             queue_push(q, p);
4724 #ifdef ENABLE_LINKED_PKGS
4725             if (has_package_link(pool, pool->solvables + p))
4726               {
4727                 int j;
4728                 Queue lq;
4729                 queue_init(&lq);
4730                 find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
4731                 for (j = 0; j < lq.count; j++)
4732                   if (solv->decisionmap[lq.elements[j]] > 0)
4733                     queue_push(q, lq.elements[j]);
4734               }
4735 #endif
4736           }
4737     }
4738   /* now process updates of userinstalled packages */
4739   if (installed && userinstalled.size)
4740     {
4741       for (i = 1; i < solv->decisionq.count; i++)
4742         {
4743           p = solv->decisionq.elements[i];
4744           if (p <= 0)
4745             continue;
4746           s = pool->solvables + p;
4747           if (!s->repo)
4748             continue;
4749           if (s->repo == installed)
4750             {
4751               if (MAPTST(&userinstalled, p - installed->start))
4752                 queue_push(q, p);
4753               continue;
4754             }
4755           /* new package, check if we replace a userinstalled one */
4756           FOR_PROVIDES(p2, pp, s->name)
4757             {
4758               Solvable *ps = pool->solvables + p2;
4759               if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
4760                 continue;
4761               if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
4762                 continue;
4763               if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
4764                 continue;
4765               queue_push(q, p);
4766               break;
4767             }
4768           if (!p2 && s->repo != installed && s->obsoletes)
4769             {
4770               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
4771               while ((obs = *obsp++) != 0)
4772                 {
4773                   FOR_PROVIDES(p2, pp, obs)
4774                     {
4775                       Solvable *ps = pool->solvables + p2;
4776                       if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
4777                         continue;
4778                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
4779                         continue;
4780                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) 
4781                         continue;
4782                       queue_push(q, p); 
4783                       break;
4784                     }
4785                   if (p2)
4786                     break;
4787                 }
4788             }
4789         }
4790     }
4791   map_free(&userinstalled);
4792   /* convert to names if asked */
4793   if ((flags & GET_USERINSTALLED_NAMES) != 0)
4794     {
4795       for (i = 0; i < q->count; i++)
4796         {
4797           s = pool->solvables + q->elements[i];
4798           q->elements[i] = s->name;
4799         }
4800     }
4801   /* sort and unify */
4802   if (q->count > 1)
4803     get_userinstalled_sort_uniq(pool, q, flags);
4804   /* invert if asked */
4805   if ((flags & GET_USERINSTALLED_INVERTED) != 0)
4806     {
4807       /* first generate queue with all installed packages */
4808       Queue invq;
4809       queue_init(&invq);
4810       for (i = 1; i < solv->decisionq.count; i++)
4811         {
4812           p = solv->decisionq.elements[i];
4813           if (p <= 0)
4814             continue;
4815           s = pool->solvables + p;
4816           if (!s->repo)
4817             continue;
4818           if ((flags & GET_USERINSTALLED_NAMES) != 0)
4819             queue_push(&invq, s->name);
4820           else
4821             queue_push(&invq, p);
4822         }
4823       /* push q on invq, just in case... */
4824       queue_insertn(&invq, invq.count, q->count, q->elements);
4825       if (invq.count > 1)
4826         get_userinstalled_sort_uniq(pool, &invq, flags);
4827       /* subtract queues (easy as they are sorted and invq is a superset of q) */
4828       if (q->count)
4829         {
4830           for (i = j = 0; i < invq.count; i++)
4831             if (invq.elements[i] == q->elements[j])
4832               {
4833                 invq.elements[i] = 0;
4834                 if (++j >= q->count)
4835                   break;
4836               }
4837           queue_empty(q);
4838         }
4839       for (i = j = 0; i < invq.count; i++)
4840         if (invq.elements[i])
4841           queue_push(q, invq.elements[i]);
4842       queue_free(&invq);
4843     }
4844 }
4845
4846 void
4847 pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
4848 {
4849   int i;
4850
4851   if (flags & GET_USERINSTALLED_INVERTED)
4852     {
4853       Queue invq;
4854       Id p, lastid;
4855       Solvable *s;
4856       int bad;
4857       if (!pool->installed)
4858         return;
4859       queue_init(&invq);
4860       FOR_REPO_SOLVABLES(pool->installed, p, s)
4861         queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
4862       queue_insertn(&invq, invq.count, q->count, q->elements);
4863       if (invq.count > 1)
4864         get_userinstalled_sort_uniq(pool, &invq, flags);
4865       /* now the fun part, add q again, sort, and remove all dups */
4866       queue_insertn(&invq, invq.count, q->count, q->elements);
4867       if (invq.count > 1)
4868         {
4869           if ((flags & GET_USERINSTALLED_NAMES) != 0)
4870             solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
4871           else
4872             solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
4873         }
4874       lastid = -1;
4875       bad = 1;
4876       for (i = 0; i < invq.count; i++)
4877         {
4878           if (invq.elements[i] == lastid)
4879             {
4880               bad = 1;
4881               continue;
4882             }
4883           if (!bad)
4884             queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
4885           bad = 0;
4886           lastid = invq.elements[i];
4887         }
4888       if (!bad)
4889         queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
4890       queue_free(&invq);
4891     }
4892   else
4893     {
4894       for (i = 0; i < q->count; i++)
4895         queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
4896     }
4897 }
4898
4899 int
4900 solver_alternatives_count(Solver *solv)
4901 {
4902   Id *elements = solv->branches.elements;
4903   int res, count;
4904   for (res = 0, count = solv->branches.count; count; res++)
4905     count -= elements[count - 2];
4906   return res;
4907 }
4908
4909 int
4910 solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
4911 {
4912   int cnt = solver_alternatives_count(solv);
4913   int count = solv->branches.count;
4914   Id *elements = solv->branches.elements;
4915   if (choices)
4916     queue_empty(choices);
4917   if (alternative <= 0 || alternative > cnt)
4918     return 0;
4919   elements += count;
4920   for (; cnt > alternative; cnt--)
4921     elements -= elements[-2];
4922   if (levelp)
4923     *levelp = elements[-1];
4924   if (fromp)
4925     *fromp = elements[-4];
4926   if (idp)
4927     *idp = elements[-3];
4928   if (chosenp)
4929     {
4930       int i;
4931       *chosenp = 0;
4932       for (i = elements[-2]; i > 4; i--)
4933         {
4934           Id p = -elements[-i];
4935           if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
4936             {
4937               *chosenp = p;
4938               break;
4939             }
4940         }
4941     }
4942   if (choices)
4943     queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
4944   return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
4945 }
4946
4947 const char *
4948 solver_select2str(Pool *pool, Id select, Id what)
4949 {
4950   const char *s;
4951   char *b;
4952   select &= SOLVER_SELECTMASK;
4953   if (select == SOLVER_SOLVABLE)
4954     return pool_solvid2str(pool, what);
4955   if (select == SOLVER_SOLVABLE_NAME)
4956     return pool_dep2str(pool, what);
4957   if (select == SOLVER_SOLVABLE_PROVIDES)
4958     {
4959       s = pool_dep2str(pool, what);
4960       b = pool_alloctmpspace(pool, 11 + strlen(s));
4961       sprintf(b, "providing %s", s);
4962       return b;
4963     }
4964   if (select == SOLVER_SOLVABLE_ONE_OF)
4965     {
4966       Id p;
4967       b = 0;
4968       while ((p = pool->whatprovidesdata[what++]) != 0)
4969         {
4970           s = pool_solvid2str(pool, p);
4971           if (b)
4972             b = pool_tmpappend(pool, b, ", ", s);
4973           else
4974             b = pool_tmpjoin(pool, s, 0, 0);
4975           pool_freetmpspace(pool, s);
4976         }
4977       return b ? b : "nothing";
4978     }
4979   if (select == SOLVER_SOLVABLE_REPO)
4980     {
4981       b = pool_alloctmpspace(pool, 20);
4982       sprintf(b, "repo #%d", what);
4983       return b;
4984     }
4985   if (select == SOLVER_SOLVABLE_ALL)
4986     return "all packages";
4987   return "unknown job select";
4988 }
4989
4990 const char *
4991 pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
4992 {
4993   Id select = how & SOLVER_SELECTMASK;
4994   const char *strstart = 0, *strend = 0;
4995   char *s;
4996   int o;
4997
4998   switch (how & SOLVER_JOBMASK)
4999     {
5000     case SOLVER_NOOP:
5001       return "do nothing";
5002     case SOLVER_INSTALL:
5003       if (select == SOLVER_SOLVABLE && pool->installed && pool->solvables[what].repo == pool->installed)
5004         strstart = "keep ", strend = " installed";
5005       else if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_NAME)
5006         strstart = "install ";
5007       else if (select == SOLVER_SOLVABLE_PROVIDES)
5008         strstart = "install a package ";
5009       else
5010         strstart = "install one of ";
5011       break;
5012     case SOLVER_ERASE:
5013       if (select == SOLVER_SOLVABLE && !(pool->installed && pool->solvables[what].repo == pool->installed))
5014         strstart = "keep ", strend = " uninstalled";
5015       else if (select == SOLVER_SOLVABLE_PROVIDES)
5016         strstart = "deinstall all packages ";
5017       else
5018         strstart = "deinstall ";
5019       break;
5020     case SOLVER_UPDATE:
5021       strstart = "update ";
5022       break;
5023     case SOLVER_WEAKENDEPS:
5024       strstart = "weaken deps of ";
5025       break;
5026     case SOLVER_MULTIVERSION:
5027       strstart = "multi version ";
5028       break;
5029     case SOLVER_LOCK:
5030       strstart = "lock ";
5031       break;
5032     case SOLVER_DISTUPGRADE:
5033       strstart = "dist upgrade ";
5034       break;
5035     case SOLVER_VERIFY:
5036       strstart = "verify ";
5037       break;
5038     case SOLVER_DROP_ORPHANED:
5039       strstart = "deinstall ", strend = " if orphaned";
5040       break;
5041     case SOLVER_USERINSTALLED:
5042       strstart = "regard ", strend = " as userinstalled";
5043       break;
5044     default:
5045       strstart = "unknown job ";
5046       break;
5047     }
5048   s = pool_tmpjoin(pool, strstart, solver_select2str(pool, select, what), strend);
5049   how &= flagmask;
5050   if ((how & ~(SOLVER_SELECTMASK|SOLVER_JOBMASK)) == 0)
5051     return s;
5052   o = strlen(s);
5053   s = pool_tmpappend(pool, s, " ", 0);
5054   if (how & SOLVER_WEAK)
5055     s = pool_tmpappend(pool, s, ",weak", 0);
5056   if (how & SOLVER_ESSENTIAL)
5057     s = pool_tmpappend(pool, s, ",essential", 0);
5058   if (how & SOLVER_CLEANDEPS)
5059     s = pool_tmpappend(pool, s, ",cleandeps", 0);
5060   if (how & SOLVER_ORUPDATE)
5061     s = pool_tmpappend(pool, s, ",orupdate", 0);
5062   if (how & SOLVER_FORCEBEST)
5063     s = pool_tmpappend(pool, s, ",forcebest", 0);
5064   if (how & SOLVER_TARGETED)
5065     s = pool_tmpappend(pool, s, ",targeted", 0);
5066   if (how & SOLVER_SETEV)
5067     s = pool_tmpappend(pool, s, ",setev", 0);
5068   if (how & SOLVER_SETEVR)
5069     s = pool_tmpappend(pool, s, ",setevr", 0);
5070   if (how & SOLVER_SETARCH)
5071     s = pool_tmpappend(pool, s, ",setarch", 0);
5072   if (how & SOLVER_SETVENDOR)
5073     s = pool_tmpappend(pool, s, ",setvendor", 0);
5074   if (how & SOLVER_SETREPO)
5075     s = pool_tmpappend(pool, s, ",setrepo", 0);
5076   if (how & SOLVER_SETNAME)
5077     s = pool_tmpappend(pool, s, ",setname", 0);
5078   if (how & SOLVER_NOAUTOSET)
5079     s = pool_tmpappend(pool, s, ",noautoset", 0);
5080   if (s[o + 1] != ',')
5081     s = pool_tmpappend(pool, s, ",?", 0);
5082   s[o + 1] = '[';
5083   return pool_tmpappend(pool, s, "]", 0);
5084 }
5085
5086 const char *
5087 solver_alternative2str(Solver *solv, int type, Id id, Id from)
5088 {
5089   Pool *pool = solv->pool;
5090   if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
5091     {
5092       const char *s = pool_dep2str(pool, id);
5093       return pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
5094     }
5095   if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
5096     {
5097       int rtype;
5098       Id depfrom, depto, dep;
5099       char buf[64];
5100       if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
5101         id = solver_rule2pkgrule(solv, id);
5102       rtype = solver_ruleinfo(solv, id, &depfrom, &depto, &dep);
5103       if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
5104         {
5105           if ((depto & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES)
5106             return pool_dep2str(pool, dep);
5107           return solver_select2str(pool, depto & SOLVER_SELECTMASK, dep);
5108         }
5109       if (rtype == SOLVER_RULE_PKG_REQUIRES)
5110         {
5111           const char *s = pool_dep2str(pool, dep);
5112           return pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, depfrom));
5113         }
5114       sprintf(buf, "Rule #%d", id);
5115       return pool_tmpjoin(pool, buf, 0, 0);
5116     }
5117   return "unknown alternative type";
5118 }
5119