summaryrefslogtreecommitdiff
path: root/src/problems.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/problems.c')
-rw-r--r--src/problems.c235
1 files changed, 202 insertions, 33 deletions
diff --git a/src/problems.c b/src/problems.c
index 2ffb6f9..7933f7c 100644
--- a/src/problems.c
+++ b/src/problems.c
@@ -24,7 +24,6 @@
#include "evr.h"
#include "solverdebug.h"
-
/**********************************************************************************/
/* a problem is an item on the solver's problem list. It can either be >0, in that
@@ -32,10 +31,9 @@
* consisting of multiple job rules.
*/
-void
+static void
solver_disableproblem(Solver *solv, Id v)
{
- Rule *r;
int i;
Id *jp;
@@ -62,30 +60,30 @@ solver_disableproblem(Solver *solv, Id v)
return;
}
solver_disablerule(solv, solv->rules + v);
-#if 0
- /* XXX: doesn't work */
- if (v >= solv->updaterules && v < solv->updaterules_end)
- {
- /* enable feature rule if we disabled the update rule */
- r = solv->rules + (v - solv->updaterules + solv->featurerules);
- if (r->p)
- solver_enablerule(solv, r);
- }
-#endif
return;
}
v = -(v + 1);
jp = solv->ruletojob.elements;
- for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+ if (solv->bestrules_pkg)
+ {
+ int ni = solv->bestrules_up - solv->bestrules;
+ for (i = 0; i < ni; i++)
+ {
+ int j = solv->bestrules_pkg[i];
+ if (j < 0 && jp[-j - solv->jobrules] == v)
+ solver_disablerule(solv, solv->rules + solv->bestrules + i);
+ }
+ }
+ for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
if (*jp == v)
- solver_disablerule(solv, r);
+ solver_disablerule(solv, solv->rules + i);
}
/*-------------------------------------------------------------------
* enableproblem
*/
-void
+static void
solver_enableproblem(Solver *solv, Id v)
{
Rule *r;
@@ -133,9 +131,174 @@ solver_enableproblem(Solver *solv, Id v)
}
v = -(v + 1);
jp = solv->ruletojob.elements;
- for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+ if (solv->bestrules_pkg)
+ {
+ int ni = solv->bestrules_up - solv->bestrules;
+ for (i = 0; i < ni; i++)
+ {
+ int j = solv->bestrules_pkg[i];
+ if (j < 0 && jp[-j - solv->jobrules] == v)
+ solver_enablerule(solv, solv->rules + solv->bestrules + i);
+ }
+ }
+ for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
if (*jp == v)
- solver_enablerule(solv, r);
+ solver_enablerule(solv, solv->rules + i);
+}
+
+
+/*-------------------------------------------------------------------
+ * turn a problem rule into a problem id by normalizing it
+ */
+static Id
+solver_ruletoproblem(Solver *solv, Id rid)
+{
+ if (rid >= solv->jobrules && rid < solv->jobrules_end)
+ rid = -(solv->ruletojob.elements[rid - solv->jobrules] + 1);
+ else if (rid >= solv->bestrules && rid < solv->bestrules_up && solv->bestrules_pkg[rid - solv->bestrules] < 0)
+ rid = -(solv->ruletojob.elements[-solv->bestrules_pkg[rid - solv->bestrules] - solv->jobrules] + 1);
+ else if (rid > solv->infarchrules && rid < solv->infarchrules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[rid].p].name;
+ while (rid > solv->infarchrules && pool->solvables[-solv->rules[rid - 1].p].name == name)
+ rid--;
+ }
+ else if (rid > solv->duprules && rid < solv->duprules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[rid].p].name;
+ while (rid > solv->duprules && pool->solvables[-solv->rules[rid - 1].p].name == name)
+ rid--;
+ }
+ return rid;
+}
+
+/*-------------------------------------------------------------------
+ * when the solver runs into a problem, it needs to disable all
+ * involved non-pkg rules and record the rules for solution
+ * generation.
+ */
+void
+solver_recordproblem(Solver *solv, Id rid)
+{
+ Id v = solver_ruletoproblem(solv, rid);
+ /* return if problem already countains our rule */
+ if (solv->problems.count)
+ {
+ int i;
+ for (i = solv->problems.count - 1; i >= 0; i--)
+ if (solv->problems.elements[i] == 0) /* end of last problem reached? */
+ break;
+ else if (solv->problems.elements[i] == v)
+ return;
+ }
+ queue_push(&solv->problems, v);
+}
+
+/*-------------------------------------------------------------------
+ * this is called when a problem is solved by disabling a rule.
+ * It calls disableproblem and then re-enables policy rules
+ */
+void
+solver_fixproblem(Solver *solv, Id rid)
+{
+ Id v = solver_ruletoproblem(solv, rid);
+ solver_disableproblem(solv, v);
+ if (v < 0)
+ solver_reenablepolicyrules(solv, -v);
+}
+
+/*-------------------------------------------------------------------
+ * disable a set of problems
+ */
+void
+solver_disableproblemset(Solver *solv, int start)
+{
+ int i;
+ for (i = start + 1; i < solv->problems.count - 1; i++)
+ solver_disableproblem(solv, solv->problems.elements[i]);
+}
+
+/*-------------------------------------------------------------------
+ * try to fix a problem by auto-uninstalling packages
+ */
+Id
+solver_autouninstall(Solver *solv, int start)
+{
+ Pool *pool = solv->pool;
+ int i;
+ int lastfeature = 0, lastupdate = 0;
+ Id v;
+ Id extraflags = -1;
+ Map *m = 0;
+
+ if (!solv->allowuninstall && !solv->allowuninstall_all)
+ {
+ if (!solv->allowuninstallmap.size)
+ return 0; /* why did we get called? */
+ m = &solv->allowuninstallmap;
+ }
+ for (i = start + 1; i < solv->problems.count - 1; i++)
+ {
+ v = solv->problems.elements[i];
+ if (v < 0)
+ extraflags &= solv->job.elements[-v - 1];
+ if (v >= solv->updaterules && v < solv->updaterules_end)
+ {
+ Rule *r;
+ if (m && !MAPTST(m, v - solv->updaterules))
+ continue;
+ /* check if identical to feature rule, we don't like that (except for orphans) */
+ r = solv->rules + solv->featurerules + (v - solv->updaterules);
+ if (!r->p)
+ {
+ /* update rule == feature rule */
+ if (v > lastfeature)
+ lastfeature = v;
+ /* prefer orphaned packages in dup mode */
+ if (solv->keep_orphans)
+ {
+ r = solv->rules + v;
+ if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules)))
+ {
+ lastfeature = v;
+ lastupdate = 0;
+ break;
+ }
+ }
+ continue;
+ }
+ if (v > lastupdate)
+ lastupdate = v;
+ }
+ }
+ if (!lastupdate && !lastfeature)
+ return 0;
+ v = lastupdate ? lastupdate : lastfeature;
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
+ /* should really be solver_fixproblem, but we know v is an update/feature rule */
+ solver_disableproblem(solv, v);
+ if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
+ {
+ /* add the package to the updatepkgs list, this will automatically turn
+ * on cleandeps mode */
+ Id p = solv->rules[v].p;
+ if (!solv->cleandeps_updatepkgs)
+ {
+ solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
+ queue_init(solv->cleandeps_updatepkgs);
+ }
+ if (p > 0)
+ {
+ int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
+ queue_pushunique(solv->cleandeps_updatepkgs, p);
+ if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
+ solver_disablepolicyrules(solv);
+ }
+ }
+ return v;
}
@@ -202,7 +365,6 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
queue_empty(refined);
if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
return;
- queue_init(&disabled);
queue_push(refined, sug);
/* re-enable all problem rules with the exception of "sug"(gestion) */
@@ -211,10 +373,14 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
for (i = 0; problem[i]; i++)
if (problem[i] != sug)
solver_enableproblem(solv, problem[i]);
-
if (sug < 0)
solver_reenablepolicyrules(solv, -sug);
- else if (sug >= solv->updaterules && sug < solv->updaterules_end)
+
+ /* here is where the feature rules come into play: if we disabled an
+ * update rule, we enable the corresponding feature rule if there is
+ * one. We do this to make the solver downgrade packages instead of
+ * deinstalling them */
+ if (sug >= solv->updaterules && sug < solv->updaterules_end)
{
/* enable feature rule */
Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
@@ -224,11 +390,15 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
enableweakrules(solv);
+ /* disabled contains all of the rules we disabled in the refinement process */
+ queue_init(&disabled);
for (;;)
{
- int njob, nfeature, nupdate, pass;
+ int nother, nfeature, nupdate, pass;
queue_empty(&solv->problems);
solver_reset(solv);
+ /* we set disablerules to zero because we are only interested in
+ * the first problem and we don't want the solver to disable the problems */
solver_run_sat(solv, 0, 0);
if (!solv->problems.count)
@@ -237,16 +407,18 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
break; /* great, no more problems */
}
disabledcnt = disabled.count;
- /* start with 1 to skip over proof index */
- njob = nfeature = nupdate = 0;
+ nother = nfeature = nupdate = 0;
for (pass = 0; pass < 2; pass++)
{
+ /* start with 1 to skip over proof index */
for (i = 1; i < solv->problems.count - 1; i++)
{
/* ignore solutions in refined */
v = solv->problems.elements[i];
if (v == 0)
break; /* end of problem reached */
+ if (!essentialok && v < 0 && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
+ continue; /* not that one! */
if (sug != v)
{
/* check if v is in the given problems list
@@ -260,14 +432,10 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
}
if (v >= solv->featurerules && v < solv->featurerules_end)
nfeature++;
- else if (v > 0)
+ else if (v > solv->updaterules && v < solv->updaterules_end)
nupdate++;
else
- {
- if (!essentialok && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
- continue; /* not that one! */
- njob++;
- }
+ nother++;
queue_push(&disabled, v);
}
if (disabled.count != disabledcnt)
@@ -280,7 +448,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
refined->count = 0;
break;
}
- if (!njob && nupdate && nfeature)
+ if (!nother && nupdate && nfeature)
{
/* got only update rules, filter out feature rules */
POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "throwing away feature rules\n");
@@ -300,14 +468,14 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
if (!nfeature && v != sug)
queue_push(refined, v); /* do not record feature rules */
solver_disableproblem(solv, v);
+ if (v < 0)
+ solver_reenablepolicyrules(solv, -v);
if (v >= solv->updaterules && v < solv->updaterules_end)
{
Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
if (r->p)
solver_enablerule(solv, r); /* enable corresponding feature rule */
}
- if (v < 0)
- solver_reenablepolicyrules(solv, -v);
}
else
{
@@ -339,6 +507,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
for (i = 0; i < disabled.count; i++)
solver_enableproblem(solv, disabled.elements[i]);
queue_free(&disabled);
+
/* reset policy rules */
for (i = 0; problem[i]; i++)
solver_enableproblem(solv, problem[i]);