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