summaryrefslogtreecommitdiff
path: root/src/solver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/solver.c')
-rw-r--r--src/solver.c906
1 files changed, 462 insertions, 444 deletions
diff --git a/src/solver.c b/src/solver.c
index 46d0ca3..f551731 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -30,6 +30,7 @@
#define RULES_BLOCK 63
+
/********************************************************************
*
* dependency check helpers
@@ -104,93 +105,66 @@ solver_splitprovides(Solver *solv, Id dep, Map *m)
}
-/*-------------------------------------------------------------------
- * solver_dep_installed
- */
-
-int
-solver_dep_installed(Solver *solv, Id dep)
-{
-#if 0
- Pool *pool = solv->pool;
- Id p, pp;
-
- if (ISRELDEP(dep))
- {
- Reldep *rd = GETRELDEP(pool, dep);
- if (rd->flags == REL_AND)
- {
- if (!solver_dep_installed(solv, rd->name))
- return 0;
- return solver_dep_installed(solv, rd->evr);
- }
- if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
- return solver_dep_installed(solv, rd->evr);
- }
- FOR_PROVIDES(p, pp, dep)
- {
- if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
- return 1;
- }
-#endif
- return 0;
-}
-
-/* mirrors solver_dep_installed, but returns 2 if a
- * dependency listed in solv->installsuppdepq was involved */
+/* mirrors solver_dep_fulfilled, but returns 2 if a new package
+ * was involved */
static int
-solver_check_installsuppdepq_dep(Solver *solv, Id dep)
+solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
{
Pool *pool = solv->pool;
Id p, pp;
- Queue *q;
+ int r;
if (ISRELDEP(dep))
{
Reldep *rd = GETRELDEP(pool, dep);
if (rd->flags == REL_AND)
{
- int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
+ int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
if (!r1)
return 0;
- r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
+ r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
if (!r2)
return 0;
return r1 == 2 || r2 == 2 ? 2 : 1;
}
if (rd->flags == REL_OR)
{
- int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
- r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
+ int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+ r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
if (!r1 && !r2)
return 0;
return r1 == 2 || r2 == 2 ? 2 : 1;
}
if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
return solver_splitprovides(solv, rd->evr, 0);
- if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
- return solver_dep_installed(solv, rd->evr);
- if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0)
+ if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
{
+ Queue *q = solv->installsuppdepq;
int i;
for (i = 0; i < q->count; i++)
if (q->elements[i] == dep || q->elements[i] == rd->name)
return 2;
}
}
+ r = 0;
FOR_PROVIDES(p, pp, dep)
if (solv->decisionmap[p] > 0)
- return 1;
- return 0;
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo && s->repo != solv->installed)
+ return 2;
+ r = 1;
+ }
+ return r;
}
static int
-solver_check_installsuppdepq(Solver *solv, Solvable *s)
+solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
{
Id sup, *supp;
supp = s->repo->idarraydata + s->supplements;
while ((sup = *supp++) != 0)
- if (solver_check_installsuppdepq_dep(solv, sup) == 2)
+ if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
return 1;
return 0;
}
@@ -208,17 +182,10 @@ autouninstall(Solver *solv, Id *problem)
{
if (v < 0)
extraflags &= solv->job.elements[-v - 1];
- if (v >= solv->featurerules && v < solv->featurerules_end)
- if (v > lastfeature)
- lastfeature = v;
if (v >= solv->updaterules && v < solv->updaterules_end)
{
- /* check if identical to feature rule */
- Id p = solv->rules[v].p;
- Rule *r;
- if (p <= 0)
- continue;
- r = solv->rules + solv->featurerules + (p - solv->installed->start);
+ /* check if identical to feature rule, we don't like that */
+ Rule *r = solv->rules + solv->featurerules + (v - solv->updaterules);
if (!r->p)
{
/* update rule == feature rule */
@@ -362,7 +329,7 @@ makeruledecisions(Solver *solv)
continue;
/* do weak rules in phase 2 */
- if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri))
+ if (ri < solv->learntrules && solv->weakrulemap.size && MAPTST(&solv->weakrulemap, ri))
continue;
v = r->p;
@@ -504,7 +471,7 @@ makeruledecisions(Solver *solv)
if (rr->p != vv /* not affecting the literal */
&& rr->p != -vv)
continue;
- if (MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */
+ if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */
continue;
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
@@ -531,6 +498,8 @@ makeruledecisions(Solver *solv)
/*
* phase 2: now do the weak assertions
*/
+ if (!solv->weakrulemap.size)
+ break; /* no weak rules, no phase 2 */
for (ii = 0; ii < solv->ruleassertions.count; ii++)
{
ri = solv->ruleassertions.elements[ii];
@@ -600,14 +569,9 @@ makewatches(Solver *solv)
int nsolvables = solv->pool->nsolvables;
solv_free(solv->watches);
- /* lower half for removals, upper half for installs */
+ /* lower half for removals, upper half for installs */
solv->watches = solv_calloc(2 * nsolvables, sizeof(Id));
-#if 1
- /* do it reverse so pkg rules get triggered first (XXX: obsolete?) */
for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
-#else
- for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
-#endif
{
if (!r->w2) /* assertions do not need watches */
continue;
@@ -678,7 +642,6 @@ propagate(Solver *solv, int level)
Id p, pkg, other_watch;
Id *dp;
Id *decisionmap = solv->decisionmap;
-
Id *watches = solv->watches + pool->nsolvables; /* place ptr in middle */
POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
@@ -686,10 +649,10 @@ propagate(Solver *solv, int level)
/* foreach non-propagated decision */
while (solv->propagate_index < solv->decisionq.count)
{
- /*
- * 'pkg' was just decided
- * negate because our watches trigger if literal goes FALSE
- */
+ /*
+ * 'pkg' was just decided
+ * negate because our watches trigger if literal goes FALSE
+ */
pkg = -solv->decisionq.elements[solv->propagate_index++];
IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
@@ -718,11 +681,11 @@ propagate(Solver *solv, int level)
solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
}
- /* 'pkg' was just decided (was set to FALSE)
- *
- * now find other literal watch, check clause
- * and advance on linked list
- */
+ /*
+ * 'pkg' was just decided (was set to FALSE), so this rule
+ * may now be unit.
+ */
+ /* find the other watch */
if (pkg == r->w1)
{
other_watch = r->w2;
@@ -734,17 +697,16 @@ propagate(Solver *solv, int level)
next_rp = &r->n2;
}
- /*
- * This term is already true (through the other literal)
- * so we have nothing to do
- */
+ /*
+ * if the other watch is true we have nothing to do
+ */
if (DECISIONMAP_TRUE(other_watch))
continue;
- /*
- * The other literal is FALSE or UNDEF
- *
- */
+ /*
+ * The other literal is FALSE or UNDEF
+ *
+ */
if (r->d)
{
@@ -755,6 +717,8 @@ propagate(Solver *solv, int level)
* and not FALSE
*
* (TRUE is also ok, in that case the rule is fulfilled)
+ * As speed matters here we do not use the FOR_RULELITERALS
+ * macro.
*/
if (r->p /* we have a 'p' */
&& r->p != other_watch /* which is not watched */
@@ -786,7 +750,7 @@ propagate(Solver *solv, int level)
if (p > 0)
POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
else
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE," -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
}
*rp = *next_rp;
@@ -853,25 +817,96 @@ propagate(Solver *solv, int level)
/*-------------------------------------------------------------------
*
+ * revert
+ * revert decisionq to a level
+ */
+
+static void
+revert(Solver *solv, int level)
+{
+ Pool *pool = solv->pool;
+ Id v, vv;
+ while (solv->decisionq.count)
+ {
+ v = solv->decisionq.elements[solv->decisionq.count - 1];
+ vv = v > 0 ? v : -v;
+ if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
+ break;
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
+ solv->decisionmap[vv] = 0;
+ solv->decisionq.count--;
+ solv->decisionq_why.count--;
+ solv->propagate_index = solv->decisionq.count;
+ }
+ while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= level)
+ solv->branches.count -= solv->branches.elements[solv->branches.count - 2];
+ if (solv->recommends_index > solv->decisionq.count)
+ solv->recommends_index = -1; /* rebuild recommends/suggests maps */
+ if (solv->decisionq.count < solv->decisioncnt_jobs)
+ solv->decisioncnt_jobs = 0;
+ if (solv->decisionq.count < solv->decisioncnt_update)
+ solv->decisioncnt_update = 0;
+ if (solv->decisionq.count < solv->decisioncnt_keep)
+ solv->decisioncnt_keep = 0;
+ if (solv->decisionq.count < solv->decisioncnt_resolve)
+ solv->decisioncnt_resolve = 0;
+ if (solv->decisionq.count < solv->decisioncnt_weak)
+ solv->decisioncnt_weak= 0;
+ if (solv->decisionq.count < solv->decisioncnt_orphan)
+ solv->decisioncnt_orphan = 0;
+}
+
+/*-------------------------------------------------------------------
+ *
+ * watch2onhighest - put watch2 on literal with highest level
+ */
+
+static inline void
+watch2onhighest(Solver *solv, Rule *r)
+{
+ int l, wl = 0;
+ Id d, v, *dp;
+
+ d = r->d < 0 ? -r->d - 1 : r->d;
+ if (!d)
+ return; /* binary rule, both watches are set */
+ dp = solv->pool->whatprovidesdata + d;
+ while ((v = *dp++) != 0)
+ {
+ l = solv->decisionmap[v < 0 ? -v : v];
+ if (l < 0)
+ l = -l;
+ if (l > wl)
+ {
+ r->w2 = dp[-1];
+ wl = l;
+ }
+ }
+}
+
+
+/*-------------------------------------------------------------------
+ *
* analyze
* and learn
*/
static int
-analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
+analyze(Solver *solv, int level, Rule *c, Rule **lrp)
{
Pool *pool = solv->pool;
- Queue r;
- Id r_buf[4];
+ Queue q;
+ Rule *r;
+ Id q_buf[8];
int rlevel = 1;
Map seen; /* global? */
- Id d, v, vv, *dp, why;
+ Id p = 0, pp, v, vv, why;
int l, i, idx;
int num = 0, l1num = 0;
int learnt_why = solv->learnt_pool.count;
Id *decisionmap = solv->decisionmap;
- queue_init_buffer(&r, r_buf, sizeof(r_buf)/sizeof(*r_buf));
+ queue_init_buffer(&q, q_buf, sizeof(q_buf)/sizeof(*q_buf));
POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
map_init(&seen, pool->nsolvables);
@@ -881,43 +916,31 @@ analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c);
queue_push(&solv->learnt_pool, c - solv->rules);
- d = c->d < 0 ? -c->d - 1 : c->d;
- dp = d ? pool->whatprovidesdata + d : 0;
- /* go through all literals of the rule */
- for (i = -1; ; i++)
+ FOR_RULELITERALS(v, pp, c)
{
- if (i == -1)
- v = c->p;
- else if (d == 0)
- v = i ? 0 : c->w2;
- else
- v = *dp++;
- if (v == 0)
- break;
-
if (DECISIONMAP_TRUE(v)) /* the one true literal */
continue;
vv = v > 0 ? v : -v;
if (MAPTST(&seen, vv))
continue;
+ MAPSET(&seen, vv); /* mark that we also need to look at this literal */
l = solv->decisionmap[vv];
if (l < 0)
l = -l;
- MAPSET(&seen, vv); /* mark that we also need to look at this literal */
if (l == 1)
l1num++; /* need to do this one in level1 pass */
else if (l == level)
num++; /* need to do this one as well */
else
{
- queue_push(&r, v); /* not level1 or conflict level, add to new rule */
+ queue_push(&q, v); /* not level1 or conflict level, add to new rule */
if (l > rlevel)
rlevel = l;
}
}
l1retry:
if (!num && !--l1num)
- break; /* all level 1 literals done */
+ break; /* all literals done */
/* find the next literal to investigate */
/* (as num + l1num > 0, we know that we'll always find one) */
@@ -933,14 +956,15 @@ l1retry:
if (num && --num == 0)
{
- *pr = -v; /* so that v doesn't get lost */
+ /* done with normal literals, now start level 1 literal processing */
+ p = -v; /* so that v doesn't get lost */
if (!l1num)
break;
POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
/* clear non-l1 bits from seen map */
- for (i = 0; i < r.count; i++)
+ for (i = 0; i < q.count; i++)
{
- v = r.elements[i];
+ v = q.elements[i];
MAPCLR(&seen, v > 0 ? v : -v);
}
/* only level 1 marks left in seen map */
@@ -954,27 +978,49 @@ l1retry:
c = solv->rules + why;
}
map_free(&seen);
-
- if (r.count == 0)
- *dr = 0;
- else if (r.count == 1 && r.elements[0] < 0)
- *dr = r.elements[0];
- else
- *dr = pool_queuetowhatprovides(pool, &r);
+ assert(p != 0);
+ assert(rlevel > 0 && rlevel < level);
IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
{
POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
- solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, *pr);
- for (i = 0; i < r.count; i++)
- solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, r.elements[i]);
+ solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
+ for (i = 0; i < q.count; i++)
+ solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, q.elements[i]);
}
/* push end marker on learnt reasons stack */
queue_push(&solv->learnt_pool, 0);
- if (whyp)
- *whyp = learnt_why;
- queue_free(&r);
solv->stats_learned++;
- return rlevel;
+
+ POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, rlevel);
+ level = rlevel;
+ revert(solv, level);
+ if (q.count < 2)
+ {
+ Id d = q.count ? q.elements[0] : 0;
+ queue_free(&q);
+ r = solver_addrule(solv, p, d, 0);
+ }
+ else
+ {
+ Id d = pool_queuetowhatprovides(pool, &q);
+ queue_free(&q);
+ r = solver_addrule(solv, p, 0, d);
+ }
+ assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
+ queue_push(&solv->learnt_why, learnt_why);
+ if (r->w2)
+ {
+ /* needs watches */
+ watch2onhighest(solv, r);
+ addwatches_rule(solv, r);
+ }
+ else
+ {
+ /* rule is an assertion */
+ queue_push(&solv->ruleassertions, r - solv->rules);
+ }
+ *lrp = r;
+ return level;
}
@@ -989,7 +1035,6 @@ l1retry:
void
solver_reset(Solver *solv)
{
- Pool *pool = solv->pool;
int i;
Id v;
@@ -1008,10 +1053,6 @@ solver_reset(Solver *solv)
/* adapt learnt rule status to new set of enabled/disabled rules */
enabledisablelearntrules(solv);
-
- /* redo all assertion rule decisions */
- makeruledecisions(solv);
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
}
@@ -1041,7 +1082,7 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen);
return;
}
- if (MAPTST(&solv->weakrulemap, why))
+ if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why))
if (!*lastweakp || why > *lastweakp)
*lastweakp = why;
/* do not add pkg rules to problem */
@@ -1079,7 +1120,7 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
/*-------------------------------------------------------------------
*
- * analyze_unsolvable
+ * analyze_unsolvable (called from setpropagatelearn)
*
* We know that the problem is not solvable. Record all involved
* rules (i.e. the "proof") into solv->learnt_pool.
@@ -1090,11 +1131,11 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
* If the proof contains at least one weak rule, we disable the
* last of them.
*
- * Otherwise we return 0 if disablerules is not set or disable
- * _all_ of the problem rules and return 1.
+ * Otherwise we return -1 if disablerules is not set or disable
+ * _all_ of the problem rules and return 0.
*
- * return: 1 - disabled some rules, try again
- * 0 - hopeless
+ * return: 0 - disabled some rules, try again
+ * -1 - hopeless
*/
static int
@@ -1102,10 +1143,10 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
{
Pool *pool = solv->pool;
Rule *r;
- Map seen; /* global to speed things up? */
+ Map involved; /* global to speed things up? */
Map rseen;
- Id d, v, vv, *dp, why;
- int l, i, idx;
+ Id pp, v, vv, why;
+ int i, idx;
Id *decisionmap = solv->decisionmap;
int oldproblemcount;
int oldlearntpoolcount;
@@ -1123,38 +1164,25 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
queue_push(&solv->problems, 0);
r = cr;
- map_init(&seen, pool->nsolvables);
+ map_init(&involved, pool->nsolvables);
map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
if (record_proof)
queue_push(&solv->learnt_pool, r - solv->rules);
lastweak = 0;
analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
- d = r->d < 0 ? -r->d - 1 : r->d;
- dp = d ? pool->whatprovidesdata + d : 0;
- for (i = -1; ; i++)
+ FOR_RULELITERALS(v, pp, r)
{
- if (i == -1)
- v = r->p;
- else if (d == 0)
- v = i ? 0 : r->w2;
- else
- v = *dp++;
- if (v == 0)
- break;
if (DECISIONMAP_TRUE(v)) /* the one true literal */
continue;
vv = v > 0 ? v : -v;
- l = solv->decisionmap[vv];
- if (l < 0)
- l = -l;
- MAPSET(&seen, vv);
+ MAPSET(&involved, vv);
}
idx = solv->decisionq.count;
while (idx > 0)
{
v = solv->decisionq.elements[--idx];
vv = v > 0 ? v : -v;
- if (!MAPTST(&seen, vv) || vv == SYSTEMSOLVABLE)
+ if (!MAPTST(&involved, vv) || vv == SYSTEMSOLVABLE)
continue;
why = solv->decisionq_why.elements[idx];
assert(why > 0);
@@ -1162,28 +1190,15 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
queue_push(&solv->learnt_pool, why);
r = solv->rules + why;
analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
- d = r->d < 0 ? -r->d - 1 : r->d;
- dp = d ? pool->whatprovidesdata + d : 0;
- for (i = -1; ; i++)
+ FOR_RULELITERALS(v, pp, r)
{
- if (i == -1)
- v = r->p;
- else if (d == 0)
- v = i ? 0 : r->w2;
- else
- v = *dp++;
- if (v == 0)
- break;
if (DECISIONMAP_TRUE(v)) /* the one true literal */
continue;
vv = v > 0 ? v : -v;
- l = solv->decisionmap[vv];
- if (l < 0)
- l = -l;
- MAPSET(&seen, vv);
+ MAPSET(&involved, vv);
}
}
- map_free(&seen);
+ map_free(&involved);
map_free(&rseen);
queue_push(&solv->problems, 0); /* mark end of this problem */
@@ -1204,7 +1219,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
if (v < 0)
solver_reenablepolicyrules(solv, -v);
solver_reset(solv);
- return 1;
+ return 0;
}
if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
@@ -1212,7 +1227,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
solv->problems.count = oldproblemcount;
solv->learnt_pool.count = oldlearntpoolcount;
solver_reset(solv);
- return 1;
+ return 0;
}
/* finish proof */
@@ -1229,84 +1244,10 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
solver_disableproblem(solv, solv->problems.elements[i]);
/* XXX: might want to enable all weak rules again */
solver_reset(solv);
- return 1;
+ return 0;
}
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
- return 0;
-}
-
-
-/********************************************************************/
-/* Decision revert */
-
-/*-------------------------------------------------------------------
- *
- * revert
- * revert decisionq to a level
- */
-
-static void
-revert(Solver *solv, int level)
-{
- Pool *pool = solv->pool;
- Id v, vv;
- while (solv->decisionq.count)
- {
- v = solv->decisionq.elements[solv->decisionq.count - 1];
- vv = v > 0 ? v : -v;
- if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
- break;
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
- solv->decisionmap[vv] = 0;
- solv->decisionq.count--;
- solv->decisionq_why.count--;
- solv->propagate_index = solv->decisionq.count;
- }
- while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= level)
- solv->branches.count -= solv->branches.elements[solv->branches.count - 2];
- if (solv->recommends_index > solv->decisionq.count)
- solv->recommends_index = -1; /* rebuild recommends/suggests maps */
- if (solv->decisionq.count < solv->decisioncnt_jobs)
- solv->decisioncnt_jobs = 0;
- if (solv->decisionq.count < solv->decisioncnt_update)
- solv->decisioncnt_update = 0;
- if (solv->decisionq.count < solv->decisioncnt_keep)
- solv->decisioncnt_keep = 0;
- if (solv->decisionq.count < solv->decisioncnt_resolve)
- solv->decisioncnt_resolve = 0;
- if (solv->decisionq.count < solv->decisioncnt_weak)
- solv->decisioncnt_weak= 0;
- if (solv->decisionq.count < solv->decisioncnt_orphan)
- solv->decisioncnt_orphan = 0;
-}
-
-
-/*-------------------------------------------------------------------
- *
- * watch2onhighest - put watch2 on literal with highest level
- */
-
-static inline void
-watch2onhighest(Solver *solv, Rule *r)
-{
- int l, wl = 0;
- Id d, v, *dp;
-
- d = r->d < 0 ? -r->d - 1 : r->d;
- if (!d)
- return; /* binary rule, both watches are set */
- dp = solv->pool->whatprovidesdata + d;
- while ((v = *dp++) != 0)
- {
- l = solv->decisionmap[v < 0 ? -v : v];
- if (l < 0)
- l = -l;
- if (l > wl)
- {
- r->w2 = dp[-1];
- wl = l;
- }
- }
+ return -1;
}
@@ -1322,7 +1263,7 @@ watch2onhighest(Solver *solv, Rule *r)
* rule to learnt rule set, make decision from learnt
* rule (always unit) and re-propagate.
*
- * returns the new solver level or 0 if unsolvable
+ * returns the new solver level or -1 if unsolvable
*
*/
@@ -1330,11 +1271,8 @@ static int
setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
{
Pool *pool = solv->pool;
- Rule *r;
- Id p = 0, d = 0;
- int l, why;
+ Rule *r, *lr;
- assert(ruleid >= 0);
if (decision)
{
level++;
@@ -1345,6 +1283,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul
queue_push(&solv->decisionq, decision);
queue_push(&solv->decisionq_why, -ruleid); /* <= 0 -> free decision */
}
+ assert(ruleid >= 0 && level > 0);
for (;;)
{
r = propagate(solv, level);
@@ -1353,36 +1292,18 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul
if (level == 1)
return analyze_unsolvable(solv, r, disablerules);
POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
- l = analyze(solv, level, r, &p, &d, &why); /* learnt rule in p and d */
- assert(l > 0 && l < level);
- POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
- level = l;
- revert(solv, level);
- r = solver_addrule(solv, p, d);
- assert(r);
- assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
- queue_push(&solv->learnt_why, why);
- if (d)
- {
- /* at least 2 literals, needs watches */
- watch2onhighest(solv, r);
- addwatches_rule(solv, r);
- }
- else
- {
- /* learnt rule is an assertion */
- queue_push(&solv->ruleassertions, r - solv->rules);
- }
+ level = analyze(solv, level, r, &lr);
/* the new rule is unit by design */
- solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
- queue_push(&solv->decisionq, p);
- queue_push(&solv->decisionq_why, r - solv->rules);
+ decision = lr->p;
+ solv->decisionmap[decision > 0 ? decision : -decision] = decision > 0 ? level : -level;
+ queue_push(&solv->decisionq, decision);
+ queue_push(&solv->decisionq_why, lr - solv->rules);
IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
{
POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: ");
- solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
+ solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, decision);
POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: ");
- solver_printrule(solv, SOLV_DEBUG_ANALYZE, r);
+ solver_printrule(solv, SOLV_DEBUG_ANALYZE, lr);
}
}
return level;
@@ -1505,7 +1426,7 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
* install best package from the queue. We add an extra package, inst, if
* provided. See comment in weak install section.
*
- * returns the new solver level or 0 if unsolvable
+ * returns the new solver level or -1 if unsolvable
*
*/
@@ -1651,8 +1572,6 @@ resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
level = selectandinstall(solv, level, dq, disablerules, i);
if (level <= olevel)
{
- if (level == 0)
- return 0; /* unsolvable */
if (level == olevel)
{
i--;
@@ -1791,6 +1710,8 @@ solver_get_flag(Solver *solv, int flag)
return solv->focus_installed;
case SOLVER_FLAG_YUM_OBSOLETES:
return solv->do_yum_obsoletes;
+ case SOLVER_FLAG_NEED_UPDATEPROVIDE:
+ return solv->needupdateprovide;
default:
break;
}
@@ -1866,14 +1787,17 @@ solver_set_flag(Solver *solv, int flag, int value)
case SOLVER_FLAG_YUM_OBSOLETES:
solv->do_yum_obsoletes = value;
break;
+ case SOLVER_FLAG_NEED_UPDATEPROVIDE:
+ solv->needupdateprovide = value;
+ break;
default:
break;
}
return old;
}
-int
-cleandeps_check_mistakes(Solver *solv, int level)
+static int
+cleandeps_check_mistakes(Solver *solv)
{
Pool *pool = solv->pool;
Rule *r;
@@ -1919,8 +1843,6 @@ cleandeps_check_mistakes(Solver *solv, int level)
solver_reenablepolicyrules_cleandeps(solv, i);
mademistake = 1;
}
- if (mademistake)
- solver_reset(solv);
return mademistake;
}
@@ -2093,7 +2015,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
int i, j, n;
Solvable *s;
Pool *pool = solv->pool;
- Id p, pp, *dp;
+ Id p, pp, *dp, postponed;
int minimizationsteps;
int installedpos = solv->installed ? solv->installed->start : 0;
@@ -2104,10 +2026,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i);
}
- POOL_DEBUG(SOLV_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count);
-
/* start SAT algorithm */
- level = 1;
+ level = 0;
systemlevel = level + 1;
POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n");
@@ -2116,7 +2036,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
/*
* here's the main loop:
- * 1) propagate new decisions (only needed once)
+ * 1) decide assertion rules and propagate
* 2) fulfill jobs
* 3) try to keep installed packages
* 4) fulfill all unresolved rules
@@ -2132,16 +2052,24 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
/*
* initial propagation of the assertions
*/
- if (level == 1)
+ if (level <= 0)
{
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagating (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
+ if (level < 0)
+ break;
+ makeruledecisions(solv);
+ level = 1;
+ if (!disablerules && solv->problems.count)
+ {
+ level = -1;
+ break;
+ }
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "initial propagate (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
if ((r = propagate(solv, level)) != 0)
{
- if (analyze_unsolvable(solv, r, disablerules))
- continue;
- level = 0;
- break; /* unsolvable */
+ level = analyze_unsolvable(solv, r, disablerules);
+ continue;
}
+ systemlevel = level + 1;
}
/*
@@ -2152,11 +2080,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
olevel = level;
level = resolve_jobrules(solv, level, disablerules, &dq);
if (level < olevel)
- {
- if (level == 0)
- break; /* unsolvable */
- continue;
- }
+ continue;
systemlevel = level + 1;
}
@@ -2273,15 +2197,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
{
olevel = level;
level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
- if (level == 0)
- {
- queue_free(&dq);
- queue_free(&dqs);
- return;
- }
if (level <= olevel)
{
- if (level == 1 || level < passlevel)
+ if (level < passlevel)
break; /* trouble */
if (level < olevel)
n = installed->start; /* redo all */
@@ -2308,11 +2226,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
}
- if (level == 0)
- break;
if (level <= olevel)
{
- if (level == 1 || level < passlevel)
+ if (level < passlevel)
break; /* trouble */
if (level < olevel)
n = installed->start; /* redo all */
@@ -2329,8 +2245,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
}
installedpos = installed->start; /* reset installedpos */
}
- if (level == 0)
- break; /* unsolvable */
systemlevel = level + 1;
if (pass < 2)
continue; /* had trouble, retry */
@@ -2343,11 +2257,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
olevel = level;
level = resolve_jobrules(solv, level, disablerules, &dq);
if (level < olevel)
- {
- if (level == 0)
- break; /* unsolvable */
- continue;
- }
+ continue;
systemlevel = level + 1;
}
@@ -2360,8 +2270,17 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
if (!solv->decisioncnt_resolve)
solv->decisioncnt_resolve = solv->decisionq.count;
POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
- for (i = 1, n = 1; n < solv->nrules; i++, n++)
+ postponed = 0;
+ for (i = 1, n = 1; ; i++, n++)
{
+ if (n >= solv->nrules)
+ {
+ if (postponed <= 0)
+ break;
+ i = postponed;
+ postponed = -1;
+ n = 1;
+ }
if (i == solv->nrules)
i = 1;
r = solv->rules + i;
@@ -2443,22 +2362,27 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
}
}
+ if (dq.count > 1 && postponed >= 0)
+ {
+ policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE_NOREORDER);
+ if (dq.count > 1)
+ {
+ if (!postponed)
+ postponed = i;
+ continue;
+ }
+ }
+
olevel = level;
level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
- if (level == 0)
- break; /* unsolvable */
- if (level < systemlevel || level == 1)
+ if (level < systemlevel)
break; /* trouble */
/* something changed, so look at all rules again */
n = 0;
}
- if (n != solv->nrules) /* ran into trouble? */
- {
- if (level == 0)
- break; /* unsolvable */
- continue; /* start over */
- }
+ if (n < solv->nrules) /* ran into trouble? */
+ continue; /* start over */
/* decide leftover cleandeps packages */
if (solv->cleandepsmap.size && solv->installed)
@@ -2586,39 +2510,15 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
/* filter out all already supplemented packages if requested */
if (!solv->addalreadyrecommended && dqs.count)
{
- /* turn off all new packages */
- for (i = 0; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p < 0)
- continue;
- s = pool->solvables + p;
- if (s->repo && s->repo != solv->installed)
- solv->decisionmap[p] = -solv->decisionmap[p];
- }
/* filter out old supplements */
for (i = j = 0; i < dqs.count; i++)
{
p = dqs.elements[i];
s = pool->solvables + p;
- if (!s->supplements)
- continue;
- if (!solver_is_supplementing(solv, s))
- dqs.elements[j++] = p;
- else if (solv->installsuppdepq && solver_check_installsuppdepq(solv, s))
+ if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s))
dqs.elements[j++] = p;
}
dqs.count = j;
- /* undo turning off */
- for (i = 0; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p < 0)
- continue;
- s = pool->solvables + p;
- if (s->repo && s->repo != solv->installed)
- solv->decisionmap[p] = -solv->decisionmap[p];
- }
}
/* multiversion doesn't mix well with supplements.
@@ -2665,8 +2565,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
else
POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
level = setpropagatelearn(solv, level, p, 0, 0);
- if (level == 0)
- break;
continue; /* back to main loop */
}
@@ -2693,8 +2591,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
if (i < dqs.count || solv->decisionq.count < decisioncount)
{
map_free(&dqmap);
- if (level == 0)
- break;
continue;
}
@@ -2749,8 +2645,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
break; /* had a problem above, quit loop */
}
map_free(&dqmap);
- if (level == 0)
- break;
continue; /* back to main loop so that all deps are checked */
}
}
@@ -2780,11 +2674,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
break;
}
if (installedone || i < solv->orphaned.count)
- {
- if (level == 0)
- break;
- continue; /* back to main loop */
- }
+ continue; /* back to main loop */
for (i = 0; i < solv->orphaned.count; i++)
{
p = solv->orphaned.elements[i];
@@ -2797,11 +2687,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
break;
}
if (i < solv->orphaned.count)
- {
- if (level == 0)
- break;
- continue; /* back to main loop */
- }
+ continue; /* back to main loop */
if (solv->brokenorphanrules)
{
solver_check_brokenorphanrules(solv, &dq);
@@ -2817,8 +2703,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
if (level < olevel)
break;
}
- if (level == 0)
- break;
continue;
}
}
@@ -2841,21 +2725,14 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
break;
}
if (p < solv->installed->end)
- {
- if (level == 0)
- break;
- continue; /* back to main loop */
- }
+ continue; /* back to main loop */
}
- if (solv->installed && solv->cleandepsmap.size)
+ if (solv->installed && solv->cleandepsmap.size && cleandeps_check_mistakes(solv))
{
- if (cleandeps_check_mistakes(solv, level))
- {
- level = 1; /* restart from scratch */
- systemlevel = level + 1;
- continue;
- }
+ solver_reset(solv);
+ level = 0; /* restart from scratch */
+ continue;
}
if (solv->solution_callback)
@@ -2884,8 +2761,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
while (i > 0 && solv->branches.elements[i - 1] > 0)
i--;
level = takebranch(solv, i, endi, "branching", disablerules);
- if (level == 0)
- break;
continue;
}
}
@@ -2941,8 +2816,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
{
minimizationsteps++;
level = takebranch(solv, lasti, lastiend, "minimizing", disablerules);
- if (level == 0)
- break;
continue; /* back to main loop */
}
}
@@ -2955,7 +2828,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
queue_free(&dq);
queue_free(&dqs);
- if (level == 0)
+ if (level < 0)
{
/* unsolvable */
solv->decisioncnt_jobs = solv->decisionq.count;
@@ -3158,9 +3031,9 @@ solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap)
* add a rule created by a job, record job number and weak flag
*/
static inline void
-solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
+solver_addjobrule(Solver *solv, Id p, Id p2, Id d, Id job, int weak)
{
- solver_addrule(solv, p, d);
+ solver_addrule(solv, p, p2, d);
queue_push(&solv->ruletojob, job);
if (weak)
queue_push(&solv->weakruleq, solv->nrules - 1);
@@ -3360,6 +3233,39 @@ deduceq2addedmap(Solver *solv, Map *addedmap)
}
}
+#ifdef ENABLE_COMPLEX_DEPS
+static int
+add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak)
+{
+ Pool *pool = solv->pool;
+ Queue bq;
+ int i, j;
+
+ queue_init(&bq);
+ i = pool_normalize_complex_dep(pool, dep, &bq, flags | CPLXDEPS_EXPAND);
+ if (i == 0 || i == 1)
+ {
+ queue_free(&bq);
+ if (i == 0)
+ solver_addjobrule(solv, -SYSTEMSOLVABLE, 0, 0, jobidx, weak);
+ return 0;
+ }
+ for (i = 0; i < bq.count; i++)
+ {
+ if (!bq.elements[i])
+ continue;
+ for (j = 0; bq.elements[i + j + 1]; j++)
+ ;
+ if (j > 1)
+ solver_addjobrule(solv, bq.elements[i], 0, pool_ids2whatprovides(pool, bq.elements + i + 1, j), jobidx, weak);
+ else
+ solver_addjobrule(solv, bq.elements[i], bq.elements[i + 1], 0, jobidx, weak);
+ i += j + 1;
+ }
+ queue_free(&bq);
+ return 1;
+}
+#endif
/*
*
@@ -3637,7 +3543,7 @@ solver_solve(Solver *solv, Queue *job)
if (how & SOLVER_FORCEBEST)
solv->bestupdatemap_all = 1;
}
- if (!solv->dupmap_all)
+ if (!solv->dupmap_all || solv->allowuninstall)
hasdupjob = 1;
break;
default:
@@ -3651,10 +3557,7 @@ solver_solve(Solver *solv, Queue *job)
* add rules for suggests, enhances
*/
oldnrules = solv->nrules;
- if (hasdupjob && !solv->updatemap_all && solv->dosplitprovides && solv->installed)
- solver_addpkgrulesforweak(solv, &addedmap);
- else
- solver_addpkgrulesforweak(solv, &addedmap);
+ solver_addpkgrulesforweak(solv, &addedmap);
POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules because of weak dependencies\n", solv->nrules - oldnrules);
#ifdef ENABLE_LINKED_PKGS
@@ -3719,7 +3622,7 @@ solver_solve(Solver *solv, Queue *job)
{
if (s->repo != installed)
{
- solver_addrule(solv, 0, 0); /* create dummy rule */
+ solver_addrule(solv, 0, 0, 0); /* create dummy rule */
continue;
}
solver_addupdaterule(solv, s, 1); /* allow s to be updated */
@@ -3747,7 +3650,7 @@ solver_solve(Solver *solv, Queue *job)
if (s->repo != installed)
{
- solver_addrule(solv, 0, 0); /* create dummy rule */
+ solver_addrule(solv, 0, 0, 0); /* create dummy rule */
continue;
}
solver_addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */
@@ -3798,6 +3701,15 @@ solver_solve(Solver *solv, Queue *job)
p = what;
d = 0;
}
+#ifdef ENABLE_COMPLEX_DEPS
+ else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what))
+ {
+ if (add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? CPLXDEPS_NAME : 0, i, weak))
+ if (how & SOLVER_FORCEBEST)
+ hasbestinstalljob = 1;
+ break;
+ }
+#endif
else
{
queue_empty(&q);
@@ -3828,7 +3740,7 @@ solver_solve(Solver *solv, Queue *job)
queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
}
}
- solver_addjobrule(solv, p, d, i, weak);
+ solver_addjobrule(solv, p, 0, d, i, weak);
if (how & SOLVER_FORCEBEST)
hasbestinstalljob = 1;
break;
@@ -3841,21 +3753,29 @@ solver_solve(Solver *solv, Queue *job)
if (select == SOLVER_SOLVABLE_ALL) /* hmmm ;) */
{
FOR_POOL_SOLVABLES(p)
- solver_addjobrule(solv, -p, 0, i, weak);
+ solver_addjobrule(solv, -p, 0, 0, i, weak);
}
else if (select == SOLVER_SOLVABLE_REPO)
{
Repo *repo = pool_id2repo(pool, what);
if (repo)
FOR_REPO_SOLVABLES(repo, p, s)
- solver_addjobrule(solv, -p, 0, i, weak);
+ solver_addjobrule(solv, -p, 0, 0, i, weak);
+ }
+#ifdef ENABLE_COMPLEX_DEPS
+ else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what))
+ {
+ /* no special "erase a specific solvable" handling? */
+ add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? (CPLXDEPS_NAME | CPLXDEPS_TODNF | CPLXDEPS_INVERT) : (CPLXDEPS_TODNF | CPLXDEPS_INVERT), i, weak);
+ break;
}
+#endif
FOR_JOB_SELECT(p, pp, select, what)
{
s = pool->solvables + p;
if (installed && s->repo == installed)
name = !name ? s->name : -1;
- solver_addjobrule(solv, -p, 0, i, weak);
+ solver_addjobrule(solv, -p, 0, 0, i, weak);
}
/* special case for "erase a specific solvable": we also
* erase all other solvables with that name, so that they
@@ -3883,7 +3803,7 @@ solver_solve(Solver *solv, Queue *job)
if (solv->rules[j].p == -p)
break;
if (j == k)
- solver_addjobrule(solv, -p, 0, i, weak); /* remove by id */
+ solver_addjobrule(solv, -p, 0, 0, i, weak); /* remove by id */
}
}
break;
@@ -3909,17 +3829,17 @@ solver_solve(Solver *solv, Queue *job)
if (select == SOLVER_SOLVABLE_ALL)
{
FOR_POOL_SOLVABLES(p)
- solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
+ solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
}
else if (select == SOLVER_SOLVABLE_REPO)
{
Repo *repo = pool_id2repo(pool, what);
if (repo)
FOR_REPO_SOLVABLES(repo, p, s)
- solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
+ solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
}
FOR_JOB_SELECT(p, pp, select, what)
- solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
+ solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
break;
case SOLVER_DISTUPGRADE:
POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
@@ -4009,11 +3929,14 @@ solver_solve(Solver *solv, Queue *job)
POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
/* create weak map */
- map_init(&solv->weakrulemap, solv->nrules);
- for (i = 0; i < solv->weakruleq.count; i++)
+ if (solv->weakruleq.count)
{
- p = solv->weakruleq.elements[i];
- MAPSET(&solv->weakrulemap, p);
+ map_grow(&solv->weakrulemap, solv->nrules);
+ for (i = 0; i < solv->weakruleq.count; i++)
+ {
+ p = solv->weakruleq.elements[i];
+ MAPSET(&solv->weakrulemap, p);
+ }
}
/* enable cleandepsmap creation if we have updatepkgs */
@@ -4045,10 +3968,6 @@ solver_solve(Solver *solv, Queue *job)
if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans)
solver_breakorphans(solv);
- /* make initial decisions based on assertion rules */
- makeruledecisions(solv);
- POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count);
-
/*
* ********************************************
* solve!
@@ -4665,21 +4584,69 @@ get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
}
+static int
+get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ int r;
+ r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0]));
+ if (r)
+ return r;
+ return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1]));
+}
+
static void
get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
{
- Id lastp = -1;
+ Id lastp = -1, lasta = -1;
int i, j;
- if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2))
+ return;
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool);
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
else
solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
- for (i = j = 0; i < q->count; i++)
- if (q->elements[i] != lastp)
- q->elements[j++] = lastp = q->elements[i];
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ for (i = j = 0; i < q->count; i += 2)
+ if (q->elements[i] != lastp || q->elements[i + 1] != lasta)
+ {
+ q->elements[j++] = lastp = q->elements[i];
+ q->elements[j++] = lasta = q->elements[i + 1];
+ }
+ }
+ else
+ {
+ for (i = j = 0; i < q->count; i++)
+ if (q->elements[i] != lastp)
+ q->elements[j++] = lastp = q->elements[i];
+ }
queue_truncate(q, j);
}
+static void
+namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job)
+{
+ int i;
+ if (!pool->installed)
+ return;
+ for (i = 0; i < q->count; i += 2)
+ {
+ Id p, pp, name = q->elements[i], arch = q->elements[i + 1];
+ FOR_PROVIDES(p, pp, name)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch))
+ continue;
+ if (job)
+ queue_push(qout, job);
+ queue_push(qout, p);
+ }
+ }
+}
+
void
solver_get_userinstalled(Solver *solv, Queue *q, int flags)
{
@@ -4789,8 +4756,20 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags)
}
}
map_free(&userinstalled);
- /* convert to names if asked */
- if ((flags & GET_USERINSTALLED_NAMES) != 0)
+
+ /* convert to desired output format */
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ int qcount = q->count;
+ queue_insertn(q, 0, qcount, 0);
+ for (i = j = 0; i < qcount; i++)
+ {
+ s = pool->solvables + q->elements[i + qcount];
+ q->elements[j++] = s->name;
+ q->elements[j++] = s->arch;
+ }
+ }
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
{
for (i = 0; i < q->count; i++)
{
@@ -4799,9 +4778,9 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags)
}
}
/* sort and unify */
- if (q->count > 1)
- get_userinstalled_sort_uniq(pool, q, flags);
- /* invert if asked */
+ get_userinstalled_sort_uniq(pool, q, flags);
+
+ /* invert if asked for */
if ((flags & GET_USERINSTALLED_INVERTED) != 0)
{
/* first generate queue with all installed packages */
@@ -4815,30 +4794,52 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags)
s = pool->solvables + p;
if (!s->repo)
continue;
- if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ queue_push2(&invq, s->name, s->arch);
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
queue_push(&invq, s->name);
else
queue_push(&invq, p);
}
/* push q on invq, just in case... */
queue_insertn(&invq, invq.count, q->count, q->elements);
- if (invq.count > 1)
- get_userinstalled_sort_uniq(pool, &invq, flags);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
/* subtract queues (easy as they are sorted and invq is a superset of q) */
- if (q->count)
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
{
- for (i = j = 0; i < invq.count; i++)
- if (invq.elements[i] == q->elements[j])
- {
- invq.elements[i] = 0;
- if (++j >= q->count)
- break;
- }
- queue_empty(q);
+ if (q->count)
+ {
+ for (i = j = 0; i < invq.count; i += 2)
+ if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1])
+ {
+ invq.elements[i] = invq.elements[i + 1] = 0;
+ j += 2;
+ if (j >= q->count)
+ break;
+ }
+ queue_empty(q);
+ }
+ for (i = 0; i < invq.count; i += 2)
+ if (invq.elements[i])
+ queue_push2(q, invq.elements[i], invq.elements[i + 1]);
+ }
+ else
+ {
+ if (q->count)
+ {
+ for (i = j = 0; i < invq.count; i++)
+ if (invq.elements[i] == q->elements[j])
+ {
+ invq.elements[i] = 0;
+ if (++j >= q->count)
+ break;
+ }
+ queue_empty(q);
+ }
+ for (i = 0; i < invq.count; i++)
+ if (invq.elements[i])
+ queue_push(q, invq.elements[i]);
}
- for (i = j = 0; i < invq.count; i++)
- if (invq.elements[i])
- queue_push(q, invq.elements[i]);
queue_free(&invq);
}
}
@@ -4848,7 +4849,7 @@ pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
{
int i;
- if (flags & GET_USERINSTALLED_INVERTED)
+ if ((flags & GET_USERINSTALLED_INVERTED) != 0)
{
Queue invq;
Id p, lastid;
@@ -4857,13 +4858,25 @@ pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
if (!pool->installed)
return;
queue_init(&invq);
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ flags &= ~GET_USERINSTALLED_NAMES; /* just in case */
FOR_REPO_SOLVABLES(pool->installed, p, s)
queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
- queue_insertn(&invq, invq.count, q->count, q->elements);
- if (invq.count > 1)
- get_userinstalled_sort_uniq(pool, &invq, flags);
- /* now the fun part, add q again, sort, and remove all dups */
- queue_insertn(&invq, invq.count, q->count, q->elements);
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ /* for namearch we convert to packages */
+ namearch2solvables(pool, q, &invq, 0);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
+ namearch2solvables(pool, q, &invq, 0);
+ flags = 0;
+ }
+ else
+ {
+ queue_insertn(&invq, invq.count, q->count, q->elements);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
+ /* now the fun part, add q again, sort, and remove all dups */
+ queue_insertn(&invq, invq.count, q->count, q->elements);
+ }
if (invq.count > 1)
{
if ((flags & GET_USERINSTALLED_NAMES) != 0)
@@ -4891,8 +4904,13 @@ pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
}
else
{
- for (i = 0; i < q->count; i++)
- queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
+ if (flags & GET_USERINSTALLED_NAMEARCH)
+ namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE);
+ else
+ {
+ for (i = 0; i < q->count; i++)
+ queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
+ }
}
}