Imported Upstream version 0.7.7
[platform/upstream/libsolv.git] / src / solver.c
index a80090d..45f9dbf 100644 (file)
@@ -431,7 +431,7 @@ propagate(Solver *solv, int level)
   Id *decisionmap = solv->decisionmap;
   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
 
-  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate level %d -----\n", level);
 
   /* foreach non-propagated decision */
   while (solv->propagate_index < solv->decisionq.count)
@@ -444,7 +444,7 @@ propagate(Solver *solv, int level)
        
       IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
         {
-         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
+         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate decision %d:", -pkg);
          solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
         }
 
@@ -462,10 +462,10 @@ propagate(Solver *solv, int level)
              continue;
            }
 
-         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+         IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
            {
-             POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
-             solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
+             POOL_DEBUG(SOLV_DEBUG_WATCHES, "  watch triggered ");
+             solver_printrule(solv, SOLV_DEBUG_WATCHES, r);
            }
 
          /*
@@ -532,12 +532,12 @@ propagate(Solver *solv, int level)
                   * if we found some p that is UNDEF or TRUE, move
                   * watch to it
                   */
-                 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+                 IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
                    {
                      if (p > 0)
-                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
+                       POOL_DEBUG(SOLV_DEBUG_WATCHES, "    -> 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_WATCHES, "    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
                    }
 
                  *rp = *next_rp;
@@ -593,7 +593,7 @@ propagate(Solver *solv, int level)
        
     } /* while we have non-decided decisions */
 
-  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end -----\n");
 
   return 0;    /* all is well */
 }
@@ -1382,7 +1382,6 @@ solver_free(Solver *solv)
   queuep_free(&solv->recommendscplxq);
   queuep_free(&solv->suggestscplxq);
   queuep_free(&solv->brokenorphanrules);
-  queuep_free(&solv->favorq);
   queuep_free(&solv->recommendsruleq);
 
   map_free(&solv->recommendsmap);
@@ -1721,12 +1720,27 @@ resolve_installed(Solver *solv, int level, int disablerules, Queue *dq)
            {
              if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
                {
+                 int j;
                  /* special multiversion handling, make sure best version is chosen */
                  if (rr->p == i && solv->decisionmap[i] >= 0)
                    queue_push(dq, i);
                  while ((p = pool->whatprovidesdata[d++]) != 0)
                    if (solv->decisionmap[p] >= 0)
                      queue_push(dq, p);
+                 for (j = 0; j < dq->count; j++)
+                   {
+                     Id p2 = dq->elements[j];
+                     if (pool->solvables[p2].repo != installed)
+                       continue;
+                     d = specialupdaters[i - installed->start];
+                     while ((p = pool->whatprovidesdata[d++]) != 0)
+                       {
+                         if (solv->decisionmap[p] >= 0 || pool->solvables[p].repo == installed)
+                           continue;
+                         if (solvable_identical(pool->solvables + p, pool->solvables + p2))
+                           queue_push(dq, p);  /* identical to installed, put it on the list so we have a repo prio */
+                       }
+                   }
                  if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start])
                    prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq);
                  if (dq->count)
@@ -1824,6 +1838,69 @@ resolve_installed(Solver *solv, int level, int disablerules, Queue *dq)
   return level;
 }
 
+/* one or more installed cleandeps packages in dq that are to be updated */
+/* we need to emulate the code in resolve_installed */
+static void
+do_cleandeps_update_filter(Solver *solv, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id *specialupdaters = solv->specialupdaters;
+  Id p, p2, pp, d;
+  Queue q;
+  int i, j, k;
+
+  queue_init(&q);
+  for (i = 0; i < dq->count; i++)
+    {
+      Id p = dq->elements[i];
+      if (p < 0)
+       p = -p;
+      if (pool->solvables[p].repo != installed || !MAPTST(&solv->cleandepsmap, p - installed->start))
+       continue;
+      queue_empty(&q);
+      /* find updaters */
+      if (specialupdaters && (d = specialupdaters[p - installed->start]) != 0)
+       {
+         while ((p2 = pool->whatprovidesdata[d++]) != 0)
+           if (solv->decisionmap[p2] >= 0)
+             queue_push(&q, p2);
+       }
+      else
+       {
+         Rule *r = solv->rules + solv->updaterules + (p - installed->start);
+         if (r->p)
+           {
+             FOR_RULELITERALS(p2, pp, r)
+               if (solv->decisionmap[p2] >= 0)
+                 queue_push(&q, p2);
+           }
+       }
+      if (q.count && solv->update_targets && solv->update_targets->elements[p - installed->start])
+        prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q);
+      /* mark all elements in dq that are in the updaters list */
+      dq->elements[i] = -p;
+      for (j = 0; j < dq->count; j++)
+       {
+          p = dq->elements[j];
+         if (p < 0)
+           continue;
+         for (k = 0; k < q.count; k++)
+           if (q.elements[k] == p)
+             {
+               dq->elements[j] = -p;
+               break;
+             }
+       }
+    }
+  /* now prune to marked elements */
+  for (i = j = 0; i < dq->count; i++)
+    if ((p = dq->elements[i]) < 0)
+      dq->elements[j++] = -p;
+  dq->count = j;
+  queue_free(&q);
+}
+
 static int
 resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
 {
@@ -1833,6 +1910,8 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
   Rule *r;
   int origlevel = level;
   Id p, *dp;
+  int focusbest = solv->focus_best && solv->do_extra_reordering;
+  Repo *installed = solv->installed;
 
   /*
    * decide
@@ -1851,6 +1930,8 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
        }
       if (i == solv->nrules)
        i = 1;
+      if (focusbest && i >= solv->featurerules)
+       continue;
       r = solv->rules + i;
       if (r->d < 0)            /* ignore disabled rules */
        continue;
@@ -1859,6 +1940,19 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
          if (r->d == 0 || solv->decisionmap[-r->p] <= 0)
            continue;
        }
+      if (focusbest && r->d != 0 && installed)
+       {
+         /* make sure at least one negative literal is from a new package */
+         if (!(r->p < 0 && pool->solvables[-r->p].repo != installed))
+           {
+             dp = pool->whatprovidesdata + r->d;
+             while ((p = *dp++) != 0)
+               if (p < 0 && solv->decisionmap[-p] > 0 && pool->solvables[-p].repo != installed)
+                 break;
+             if (!p)
+               continue;               /* sorry */
+           }
+       }
       if (dq->count)
        queue_empty(dq);
       if (r->d == 0)
@@ -1919,15 +2013,25 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
       /* prune to cleandeps packages */
       if (solv->cleandepsmap.size && solv->installed)
        {
+         int cleandeps_update = 0;
          Repo *installed = solv->installed;
          for (j = 0; j < dq->count; j++)
            if (pool->solvables[dq->elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq->elements[j] - installed->start))
-             break;
+             {
+               if (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - installed->start)))
+                 {
+                   cleandeps_update = 1;               /* cleandeps package is marked for update */
+                   continue;
+                 }
+               break;
+             }
          if (j < dq->count)
            {
              dq->elements[0] = dq->elements[j];
              queue_truncate(dq, 1);
            }
+         else if (cleandeps_update)
+           do_cleandeps_update_filter(solv, dq);       /* special update filter */
        }
 
       if (dq->count > 1 && postponed >= 0)
@@ -3208,36 +3312,44 @@ add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak)
 }
 #endif
 
-/* sort by package id, last entry wins */
-static int
-setup_favormap_cmp(const void *ap, const void *bp, void *dp)
-{
-  const Id *a = ap, *b = bp;
-  if ((*a - *b) != 0)
-    return *a - *b;
-  return (b[1] < 0 ? -b[1] : b[1]) - (a[1] < 0 ? -a[1] : a[1]);
-}
-
 static void
 setup_favormap(Solver *solv)
 {
-  Queue *q = solv->favorq;
+  Queue *job = &solv->job;
   Pool *pool = solv->pool;
-  int i;
-  Id oldp = 0;
-  if (q->count > 2)
-    solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormap_cmp, solv);
+  int i, idx;
+  Id p, pp, how, what, select;
+
+  solv_free(solv->favormap);
   solv->favormap = solv_calloc(pool->nsolvables, sizeof(Id));
-  solv->havedisfavored = 0;
-  for (i = 0; i < q->count; i += 2)
+  for (i = 0; i < job->count; i += 2)
     {
-      Id p = q->elements[i];
-      if (p == oldp)
+      how = job->elements[i];
+      if ((how & SOLVER_JOBMASK) != SOLVER_FAVOR && (how & SOLVER_JOBMASK) != SOLVER_DISFAVOR)
        continue;
-      oldp = p;
-      solv->favormap[p] = q->elements[i + 1];
-      if (q->elements[i + 1] < 0)
-       solv->havedisfavored = 1;
+      what = job->elements[i + 1];
+      select = how & SOLVER_SELECTMASK;
+      idx = (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? i + 1 : -(i + 1);
+      if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Repo *repo = pool_id2repo(pool, what);
+         if (repo)
+           {
+             Solvable *s;
+             FOR_REPO_SOLVABLES(repo, p, s)
+               {
+                 solv->favormap[p] = idx;
+                 if (idx < 0)
+                   solv->havedisfavored = 1;
+               }
+           }
+       }
+      FOR_JOB_SELECT(p, pp, select, what)
+       {
+         solv->favormap[p] = idx;
+         if (idx < 0)
+           solv->havedisfavored = 1;
+       }
     }
 }
 
@@ -3263,6 +3375,8 @@ solver_solve(Solver *solv, Queue *job)
   int now, solve_start;
   int needduprules = 0;
   int hasbestinstalljob = 0;
+  int hasfavorjob = 0;
+  int haslockjob = 0;
 
   solve_start = solv_timems(0);
 
@@ -3270,6 +3384,7 @@ solver_solve(Solver *solv, Queue *job)
   POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
   POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
   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);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "dupallowdowngrade=%d, dupallownamechange=%d, dupallowarchchange=%d, dupallowvendorchange=%d\n", solv->dup_allowdowngrade, solv->dup_allownamechange, solv->dup_allowarchchange, solv->dup_allowvendorchange);
   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors);
   POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d onlynamespacerecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended, solv->only_namespace_recommended);
@@ -3773,6 +3888,10 @@ solver_solve(Solver *solv, Queue *job)
                  name_s = s;
                }
              solver_addjobrule(solv, -p, 0, 0, i, weak);
+#ifdef ENABLE_LINKED_PKGS
+             if (solv->instbuddy && installed && s->repo == installed && solv->instbuddy[p - installed->start] > 1)
+               solver_addjobrule(solv, -solv->instbuddy[p - installed->start], 0, 0, i, weak);
+#endif
            }
          /* special case for "erase a specific solvable": we also
           * erase all other solvables with that name, so that they
@@ -3840,7 +3959,16 @@ solver_solve(Solver *solv, Queue *job)
                }
            }
          FOR_JOB_SELECT(p, pp, select, what)
-           solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
+           {
+             s = pool->solvables + p;
+             solver_addjobrule(solv, installed && s->repo == installed ? p : -p, 0, 0, i, weak);
+#ifdef ENABLE_LINKED_PKGS
+             if (solv->instbuddy && installed && s->repo == installed && solv->instbuddy[p - installed->start] > 1)
+               solver_addjobrule(solv, solv->instbuddy[p - installed->start], 0, 0, i, weak);
+#endif
+           }
+         if (solv->nrules != oldnrules)
+           haslockjob = 1;
          break;
        case SOLVER_DISTUPGRADE:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
@@ -3857,15 +3985,7 @@ solver_solve(Solver *solv, Queue *job)
        case SOLVER_FAVOR:
        case SOLVER_DISFAVOR:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s %s\n", (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? "favor" : "disfavor", solver_select2str(pool, select, what));
-         FOR_JOB_SELECT(p, pp, select, what)
-           {
-             if (!solv->favorq)
-               {
-                 solv->favorq = solv_calloc(1, sizeof(Queue));
-                 queue_init(solv->favorq);
-               }
-             queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? i + 1 : -(i + 1));
-           }
+         hasfavorjob = 1;
          break;
        default:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
@@ -3887,8 +4007,8 @@ solver_solve(Solver *solv, Queue *job)
   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
   solv->jobrules_end = solv->nrules;
 
-  /* sort favorq and transform it into two maps */
-  if (solv->favorq)
+  /* create favormap if we have favor jobs */
+  if (hasfavorjob)
     setup_favormap(solv);
 
   /* now create infarch and dup rules */
@@ -3908,7 +4028,7 @@ solver_solve(Solver *solv, Queue *job)
 #endif
 
   if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
-    solver_addbestrules(solv, hasbestinstalljob);
+    solver_addbestrules(solv, hasbestinstalljob, haslockjob);
   else
     solv->bestrules = solv->bestrules_end = solv->bestrules_up = solv->nrules;
 
@@ -3920,7 +4040,7 @@ solver_solve(Solver *solv, Queue *job)
   else
     solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
 
-  if (solv->havedisfavored && solv->strongrecommends)
+  if (solv->havedisfavored && solv->strongrecommends && solv->recommendsruleq)
     solver_addrecommendsrules(solv);
   else
     solv->recommendsrules = solv->recommendsrules_end = solv->nrules;