- clean up update/feature rule handling in allowuninstall case. Automatically add...
authorMichael Schroeder <mls@suse.de>
Mon, 5 Mar 2012 13:01:21 +0000 (14:01 +0100)
committerMichael Schroeder <mls@suse.de>
Mon, 5 Mar 2012 13:01:21 +0000 (14:01 +0100)
We no longer make the update/featurerule weak, but use a "autouninstall" function
instead that checks if we can solve the problem by removing a package. We also
automatically add CLEANDEPS in that case if all job rules in the problem have
CLEANDEPS set.

src/libsolv.ver
src/problems.c
src/problems.h
src/rules.c
src/solver.c

index 0b852da..fcb95b3 100644 (file)
@@ -320,6 +320,7 @@ SOLV_1.0 {
                solver_solutionelement2str;
                solver_solutionelement_count;
                solver_solutionelement_internalid;
+               solver_solutionelement_extrajobflags;
                solver_solve;
                solver_take_solution;
                solver_take_solutionelement;
index 3a1409d..33bb099 100644 (file)
@@ -531,6 +531,7 @@ create_solutions(Solver *solv, int probnr, int solidx)
   int essentialok;
   unsigned int now;
   int oldmistakes = solv->cleandeps_mistakes ? solv->cleandeps_mistakes->count : 0;
+  Id extraflags = -1;
 
   now = solv_timems(0);
   queue_init(&redoq);
@@ -554,7 +555,11 @@ create_solutions(Solver *solv, int probnr, int solidx)
       if (!v)
        break;
       queue_push(&problem, v);
+      if (v < 0)
+       extraflags &= solv->job.elements[-v - 1];
     }
+  if (extraflags == -1)
+    extraflags = 0;
   if (problem.count > 1)
     solv_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job);
   queue_push(&problem, 0);     /* mark end for refine_suggestion */
@@ -609,6 +614,7 @@ create_solutions(Solver *solv, int probnr, int solidx)
       queue_push(&solv->solutions, 0); /* add end marker */
       queue_push(&solv->solutions, 0); /* add end marker */
       queue_push(&solv->solutions, problem.elements[i]);       /* just for bookkeeping */
+      queue_push(&solv->solutions, extraflags & SOLVER_CLEANDEPS);     /* our extraflags */
       solv->solutions.elements[solidx + 1 + nsol++] = solstart;
     }
   solv->solutions.elements[solidx + 1 + nsol] = 0;     /* end marker */
@@ -697,6 +703,14 @@ solver_solutionelement_internalid(Solver *solv, Id problem, Id solution)
   return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 3];
 }
 
+Id
+solver_solutionelement_extrajobflags(Solver *solv, Id problem, Id solution)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  solidx = solv->solutions.elements[solidx + solution];
+  return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 4];
+}
+
 
 /*
  *  return the next item of the proposed solution
@@ -738,7 +752,7 @@ solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, I
 }
 
 void
-solver_take_solutionelement(Solver *solv, Id p, Id rp, Queue *job)
+solver_take_solutionelement(Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job)
 {
   int i;
 
@@ -751,11 +765,11 @@ solver_take_solutionelement(Solver *solv, Id p, Id rp, Queue *job)
   if (rp <= 0 && p <= 0)
     return;    /* just in case */
   if (rp > 0)
-    p = SOLVER_INSTALL|SOLVER_SOLVABLE;
+    p = SOLVER_INSTALL|SOLVER_SOLVABLE|extrajobflags;
   else
     {
       rp = p;
-      p = SOLVER_ERASE|SOLVER_SOLVABLE;
+      p = SOLVER_ERASE|SOLVER_SOLVABLE|extrajobflags;
     }
   for (i = 0; i < job->count; i += 2)
     if (job->elements[i] == p && job->elements[i + 1] == rp)
@@ -767,8 +781,9 @@ void
 solver_take_solution(Solver *solv, Id problem, Id solution, Queue *job)
 {
   Id p, rp, element = 0;
+  Id extrajobflags = solver_solutionelement_extrajobflags(solv, problem, solution);
   while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
-    solver_take_solutionelement(solv, p, rp, job);
+    solver_take_solutionelement(solv, p, rp, extrajobflags, job);
 }
 
 
index cd56aa2..d01f2fa 100644 (file)
@@ -34,9 +34,10 @@ unsigned int solver_solution_count(struct _Solver *solv, Id problem);
 Id solver_next_solution(struct _Solver *solv, Id problem, Id solution);
 unsigned int solver_solutionelement_count(struct _Solver *solv, Id problem, Id solution);
 Id solver_solutionelement_internalid(struct _Solver *solv, Id problem, Id solution);
+Id solver_solutionelement_extrajobflags(struct _Solver *solv, Id problem, Id solution);
 Id solver_next_solutionelement(struct _Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp);
 
-void solver_take_solutionelement(struct _Solver *solv, Id p, Id rp, Queue *job);
+void solver_take_solutionelement(struct _Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job);
 void solver_take_solution(struct _Solver *solv, Id problem, Id solution, Queue *job);
 
 Id solver_findproblemrule(struct _Solver *solv, Id problem);
index 0530ccc..fd83c62 100644 (file)
@@ -2545,6 +2545,15 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
   if (unneeded)
     queue_empty(&iq);  /* just in case... */
 
+  /* clear userinstalled bit for the packages we really want to delete/update */
+  for (i = 0; i < iq.count; i++)
+    {
+      p = iq.elements[i];
+      if (pool->solvables[p].repo != installed)
+       continue;
+      MAPCLR(&userinstalled, p - installed->start);
+    }
+
   for (p = installed->start; p < installed->end; p++)
     {
       if (pool->solvables[p].repo != installed)
index 27a6f4c..54ca285 100644 (file)
@@ -103,6 +103,66 @@ solver_dep_installed(Solver *solv, Id dep)
 }
 
 
+static Id
+autouninstall(Solver *solv, Id *problem)
+{
+  Pool *pool = solv->pool;
+  int i;
+  int lastfeature = 0, lastupdate = 0;
+  Id v;
+  Id extraflags = -1;
+
+  for (i = 0; (v = problem[i]) != 0; i++)
+    {
+      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;
+         if (p <= 0)
+           continue;
+         Rule *r = solv->rules + solv->featurerules + (p - solv->installed->start);
+         if (!r->p)
+           {
+             /* update rule == feature rule */
+             if (v > lastfeature)
+               lastfeature = v;
+             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);
+  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;
+}
 
 /************************************************************************/
 
@@ -122,6 +182,7 @@ makeruledecisions(Solver *solv)
   Id v, vv;
   int decisionstart;
   int record_proof = 1;
+  int oldproblemcount;
 
   /* The system solvable is always installed first */
   assert(solv->decisionq.count == 0);
@@ -129,6 +190,7 @@ makeruledecisions(Solver *solv)
   queue_push(&solv->decisionq_why, 0);
   solv->decisionmap[SYSTEMSOLVABLE] = 1;       /* installed at level '1' */
 
+  /* note that the ruleassertions queue is ordered */
   decisionstart = solv->decisionq.count;
   for (ii = 0; ii < solv->ruleassertions.count; ii++)
     {
@@ -146,9 +208,6 @@ makeruledecisions(Solver *solv)
        
       if (!solv->decisionmap[vv])          /* if not yet decided */
        {
-           /*
-            * decide !
-            */
          queue_push(&solv->decisionq, v);
          queue_push(&solv->decisionq_why, r - solv->rules);
          solv->decisionmap[vv] = v > 0 ? 1 : -1;
@@ -162,22 +221,22 @@ makeruledecisions(Solver *solv)
            }
          continue;
        }
-       /*
-        * check previous decision: is it sane ?
-        */
-       
+
+      /*
+       * check against previous decision: is there a conflict ?
+       */
       if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
        continue;
       if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
        continue;
        
-        /*
-        * found a conflict!
-        
-        * The rule (r) we're currently processing says something
-        * different (v = r->p) than a previous decision (decisionmap[abs(v)])
-        * on this literal
-        */
+      /*
+       * found a conflict!
+       * 
+       * The rule (r) we're currently processing says something
+       * different (v = r->p) than a previous decision (decisionmap[abs(v)])
+       * on this literal
+       */
        
       if (ri >= solv->learntrules)
        {
@@ -197,14 +256,13 @@ makeruledecisions(Solver *solv)
        if (solv->decisionq.elements[i] == -v)
          break;
       assert(i < solv->decisionq.count);         /* assert that we found it */
+      oldproblemcount = solv->problems.count;
        
       /*
        * conflict with system solvable ?
        */
-       
       if (v == -SYSTEMSOLVABLE)
        {
-         /* conflict with system solvable */
          if (record_proof)
            {
              queue_push(&solv->problems, solv->learnt_pool.count);
@@ -220,6 +278,8 @@ makeruledecisions(Solver *solv)
            v = ri;
          queue_push(&solv->problems, v);
          queue_push(&solv->problems, 0);
+         if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
+           solv->problems.count = oldproblemcount;
          solver_disableproblem(solv, v);
          continue;
        }
@@ -229,10 +289,8 @@ makeruledecisions(Solver *solv)
       /*
        * conflict with an rpm rule ?
        */
-
       if (solv->decisionq_why.elements[i] < solv->rpmrules_end)
        {
-         /* conflict with rpm rule assertion */
          if (record_proof)
            {
              queue_push(&solv->problems, solv->learnt_pool.count);
@@ -250,6 +308,8 @@ makeruledecisions(Solver *solv)
            v = ri;
          queue_push(&solv->problems, v);
          queue_push(&solv->problems, 0);
+         if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
+           solv->problems.count = oldproblemcount;
          solver_disableproblem(solv, v);
          continue;
        }
@@ -271,11 +331,10 @@ makeruledecisions(Solver *solv)
 
       POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
 
-        /*
-        * push all of our rules (can only be feature or job rules)
-        * asserting this literal on the problem stack
-        */
-       
+      /*
+       * push all of our rules (can only be feature or job rules)
+       * asserting this literal on the problem stack
+       */
       for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
        {
          if (rr->d < 0                          /* disabled */
@@ -288,19 +347,21 @@ makeruledecisions(Solver *solv)
            continue;
            
          POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
-           
           solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
            
          v = i;
-           /* is is a job rule ? */
          if (i >= solv->jobrules && i < solv->jobrules_end)
            v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
-           
          queue_push(&solv->problems, v);
-         solver_disableproblem(solv, v);
        }
       queue_push(&solv->problems, 0);
 
+      if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
+       solv->problems.count = oldproblemcount;
+
+      for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
+        solver_disableproblem(solv, solv->problems.elements[i]);
+
       /*
        * start over
        * (back up from decisions)
@@ -1023,7 +1084,6 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
 
   if (lastweak)
     {
-      Id v;
       /* disable last weak rule */
       solv->problems.count = oldproblemcount;
       solv->learnt_pool.count = oldlearntpoolcount;
@@ -1042,6 +1102,14 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
       return 1;
     }
 
+  if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
+    {
+      solv->problems.count = oldproblemcount;
+      solv->learnt_pool.count = oldlearntpoolcount;
+      solver_reset(solv);
+      return 1;
+    }
+
   /* finish proof */
   if (record_proof)
     {
@@ -2710,28 +2778,9 @@ solver_solve(Solver *solv, Queue *job)
              continue;
            }
          if (!solver_samerule(solv, r, sr))
-           {
-             /* identical rule, kill unneeded one */
-             if (solv->allowuninstall)
-               {
-                 /* keep feature rule, make it weak */
-                 memset(r, 0, sizeof(*r));
-                 queue_push(&solv->weakruleq, sr - solv->rules);
-               }
-             else
-               {
-                 /* keep update rule */
-                 memset(sr, 0, sizeof(*sr));
-               }
-           }
-         else if (solv->allowuninstall)
-           {
-             /* make both feature and update rule weak */
-             queue_push(&solv->weakruleq, r - solv->rules);
-             queue_push(&solv->weakruleq, sr - solv->rules);
-           }
+           memset(sr, 0, sizeof(*sr));         /* delete unneeded feature rule */
          else
-           solver_disablerule(solv, sr);
+           solver_disablerule(solv, sr);       /* disable feature rule */
        }
       /* consistency check: we added a rule for _every_ installed solvable */
       assert(solv->nrules - solv->updaterules == installed->end - installed->start);