Imported Upstream version 0.7.11
[platform/upstream/libsolv.git] / src / rules.c
index b6cd582..f735e5d 100644 (file)
@@ -498,6 +498,16 @@ add_package_link(Solver *solv, Solvable *s, Map *m, Queue *workq)
 
 #ifdef ENABLE_COMPLEX_DEPS
 
+#ifdef SUSE
+static inline int
+suse_isptf(Pool *pool, Solvable *s)
+{
+  if (!strncmp("ptf-", pool_id2str(pool, s->name), 4))
+    return 1;
+  return 0;
+}
+#endif
+
 static void
 add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *workq, Map *m)
 {
@@ -511,6 +521,10 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w
   /* CNF expansion for requires, DNF + INVERT expansion for conflicts */
   if (type == SOLVER_RULE_PKG_CONFLICTS)
     flags |= CPLXDEPS_TODNF | CPLXDEPS_EXPAND | CPLXDEPS_INVERT;
+#ifdef SUSE
+  if (type == SOLVER_RULE_PKG_REQUIRES && suse_isptf(pool, pool->solvables + p))
+    flags |= CPLXDEPS_NAME;    /* do not match provides */
+#endif
 
   i = pool_normalize_complex_dep(pool, dep, &bq, flags);
   /* handle special cases */
@@ -651,6 +665,34 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w
 
 #endif
 
+#ifdef ENABLE_CONDA
+void
+add_conda_constrains_rule(Solver *solv, Id n, Id dep, int dontfix)
+{
+  Pool *pool = solv->pool;
+  Reldep *rd;
+  Id p, pp, pdep;
+  if (!ISRELDEP(dep))
+    return;
+  rd = GETRELDEP(pool, dep);
+  pdep = pool_whatprovides(pool, dep);
+  FOR_PROVIDES(p, pp, rd->name)
+    {
+      Id p2;
+      if (p == n)
+       continue;
+      if (dontfix && pool->solvables[p].repo == solv->installed)
+       continue;
+      while ((p2 = pool->whatprovidesdata[pdep]) != 0 && p2 < p)
+       pdep++;
+      if (p == p2)
+       pdep++;
+      else
+        addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_CONSTRAINS, dep);
+    }
+}
+#endif
+
 /*-------------------------------------------------------------------
  *
  * add dependency rules for solvable
@@ -679,8 +721,8 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
 
   Queue workq; /* list of solvables we still have to work on */
   Id workqbuf[64];
-  Queue prereqq;       /* list of pre-req ids to ignore */
-  Id prereqbuf[16];
+  Queue depq;  /* list of pre-req ids to ignore */
+  Id depqbuf[16];
 
   int i;
   int dontfix;         /* ignore dependency errors for installed solvables */
@@ -696,7 +738,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
   queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
   queue_push(&workq, s - pool->solvables);     /* push solvable Id to work queue */
 
-  queue_init_buffer(&prereqq, prereqbuf, sizeof(prereqbuf)/sizeof(*prereqbuf));
+  queue_init_buffer(&depq, depqbuf, sizeof(depqbuf)/sizeof(*depqbuf));
 
   /* loop until there's no more work left */
   while (workq.count)
@@ -756,20 +798,18 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
                {
                  if (installed && s->repo == installed)
                    {
-                     if (prereqq.count)
-                       queue_empty(&prereqq);
-                     solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &prereqq);
-                     filterpre = prereqq.count;
+                     solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &depq);
+                     filterpre = depq.count;
                    }
                  continue;
                }
              if (filterpre)
                {
-                 /* check if this id is filtered. assumes that prereqq.count is small */
-                 for (i = 0; i < prereqq.count; i++)
-                   if (req == prereqq.elements[i])
+                 /* check if this id is filtered. assumes that depq.count is small */
+                 for (i = 0; i < depq.count; i++)
+                   if (req == depq.elements[i])
                      break;
-                 if (i < prereqq.count)
+                 if (i < depq.count)
                    {
                      POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s: ignoring filtered pre-req dependency %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
                      continue;
@@ -882,6 +922,15 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
            }
        }
 
+#ifdef ENABLE_CONDA
+      if (pool->disttype == DISTTYPE_CONDA)
+       {
+         solvable_lookup_idarray(s, SOLVABLE_CONSTRAINS, &depq);
+         for (i = 0; i < depq.count; i++)
+           add_conda_constrains_rule(solv, n, depq.elements[i], dontfix);
+       }
+#endif
+
       /* that's all we check for src packages */
       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
        continue;
@@ -1085,7 +1134,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
            }
        }
     }
-  queue_free(&prereqq);
+  queue_free(&depq);
   queue_free(&workq);
 }
 
@@ -1328,6 +1377,31 @@ solver_addfeaturerule(Solver *solv, Solvable *s)
     }
 }
 
+/* check if multiversion solvable s2 has an obsoletes for installed solvable s */
+static int
+is_multiversion_obsoleteed(Pool *pool, Solvable *s, Solvable *s2)
+{
+  Id *wp, obs, *obsp;
+
+  if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+    return 0;
+  obsp = s2->repo->idarraydata + s2->obsoletes;
+  if (!pool->obsoleteusesprovides)
+    {
+      while ((obs = *obsp++) != 0)
+        if (pool_match_nevr(pool, s, obs))
+         return 1;
+    }
+  else
+    {
+      while ((obs = *obsp++) != 0)
+        for (wp = pool_whatprovides_ptr(pool, obs); *wp; wp++)
+         if (pool->solvables + *wp == s)
+           return 1;
+    }
+  return 0;
+}
+
 /*-------------------------------------------------------------------
  *
  * add rule for update
@@ -1348,6 +1422,14 @@ solver_addupdaterule(Solver *solv, Solvable *s)
   int dupinvolved = 0;
 
   p = s - pool->solvables;
+
+  if (pool->considered && pool_disabled_solvable(pool, s))
+    {
+      /* disabled installed solvables must stay installed */
+      solver_addrule(solv, p, 0, 0);
+      return;
+    }
+
   /* Orphan detection. We cheat by looking at the feature rule, which
    * we already calculated */
   r = solv->rules + solv->featurerules + (p - solv->installed->start);
@@ -1389,9 +1471,8 @@ solver_addupdaterule(Solver *solv, Solvable *s)
              if (MAPTST(&solv->multiversion, qs.elements[i]))
                {
                  Solvable *ps = pool->solvables + qs.elements[i];
-                 /* if keepexplicitobsoletes is set and the name is different,
-                  * we assume that there is an obsoletes. XXX: not 100% correct */
-                 if (solv->keepexplicitobsoletes && ps->name != s->name)
+                 /* check if there is an explicit obsoletes */
+                 if (solv->keepexplicitobsoletes && ps->obsoletes && is_multiversion_obsoleteed(pool, s, ps))
                    {
                      qs.elements[j++] = qs.elements[i];
                      continue;
@@ -1575,13 +1656,16 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
            }
        }
       if (first)
-       continue;
+       continue;               /* not the first in the group */
+
+      if (!bestscore)
+       continue;               /* did not find a score for this group */
 
       /* speed up common case where installed package already has best arch */
       if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
        allowedarchs.count--;   /* installed arch is best */
 
-      if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestscore)
+      if (allowedarchs.count && pool->implicitobsoleteusescolors && installed)
        {
          /* need an extra pass for lockstep checking: we only allow to keep an inferior arch
           * if the corresponding installed package is not lock-stepped */
@@ -1626,7 +1710,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
          if (ps->name != s->name || !MAPTST(addedmap, p))
            continue;
          a = pool_arch2score(pool, ps->arch);
-         if (a != 1 && bestscore && ((a ^ bestscore) & 0xffff0000) != 0)
+         if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
            {
              if (installed && ps->repo == installed)
                {
@@ -1979,6 +2063,8 @@ solver_addduprules(Solver *solv, Map *addedmap)
            continue;
          if (installed && ps->repo == installed)
            {
+             if (pool->considered && pool_disabled_solvable(pool, ps))
+               continue;               /* always keep disabled installed packages */
              if (!MAPTST(&solv->dupmap, p))
                {
                  Id ip, ipp;
@@ -2067,6 +2153,97 @@ reenableduprule(Solver *solv, Id name)
     }
 }
 
+/***********************************************************************
+ ***
+ ***  Black rule part
+ ***/
+
+static inline void
+disableblackrule(Solver *solv, Id p)
+{
+  Rule *r;
+  int i;
+  for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++)
+    if (r->p == -p)
+      solver_disablerule(solv, r);
+}
+
+static inline void
+reenableblackrule(Solver *solv, Id p)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  int i;
+  for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++)
+    if (r->p == -p)
+      {
+       solver_enablerule(solv, r);
+       IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+         {
+           POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+           solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+         }
+      }
+}
+
+void
+solver_addblackrules(Solver *solv)
+{
+  int i;
+  Id how, select, what, p, pp;
+  Queue *job = &solv->job;
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Map updatemap;
+
+  map_init(&updatemap, 0);
+  solv->blackrules = solv->nrules;
+  if (installed)
+    {
+      for (i = 0; i < job->count; i += 2)
+       {
+         how = job->elements[i];
+         select = job->elements[i] & SOLVER_SELECTMASK;
+         what = job->elements[i + 1];
+         switch (how & SOLVER_JOBMASK)
+           {
+           case SOLVER_BLACKLIST:
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (s->repo != installed)
+                   continue;
+                 if (!updatemap.size)
+                   map_grow(&updatemap, pool->ss.nstrings);
+                 if (s->name > 0 && s->name < pool->ss.nstrings)
+                   MAPSET(&updatemap, s->name);
+               }
+           }
+       }
+    }
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      select = job->elements[i] & SOLVER_SELECTMASK;
+      what = job->elements[i + 1];
+      switch (how & SOLVER_JOBMASK)
+       {
+       case SOLVER_BLACKLIST:
+         FOR_JOB_SELECT(p, pp, select, what)
+           {
+             Solvable *s = pool->solvables + p;
+             if (s->repo == installed)
+               continue;
+             if (updatemap.size && s->name > 0 && s->name < pool->ss.nstrings && MAPTST(&updatemap, s->name))
+               continue;       /* installed package with same name is already blacklisted */
+             solver_addrule(solv, -p, 0, 0);
+           }
+         break;
+       }
+    }
+  map_free(&updatemap);
+  solv->blackrules_end = solv->nrules;
+}
 
 /***********************************************************************
  ***
@@ -2080,6 +2257,7 @@ reenableduprule(Solver *solv, Id name)
 #define DISABLE_UPDATE 1
 #define DISABLE_INFARCH        2
 #define DISABLE_DUP    3
+#define DISABLE_BLACK  4
 
 static void
 jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
@@ -2179,6 +2357,16 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
                }
            }
        }
+      if ((set & SOLVER_SETEVR) != 0 && solv->blackrules != solv->blackrules_end)
+        {
+         if (select == SOLVER_SOLVABLE)
+           queue_push2(q, DISABLE_BLACK, what);
+         else
+           {
+             FOR_JOB_SELECT(p, pp, select, what)
+               queue_push2(q, DISABLE_BLACK, p);
+           }
+        }
       if (!installed || installed->end == installed->start)
        return;
       /* now the hard part: disable some update rules */
@@ -2189,7 +2377,7 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
          if (pool->solvables[p].repo == installed)
            return;
          if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes)
-           return;
+           return;             /* will not obsolete anything, so just return */
        }
       omap.size = 0;
       qstart = q->count;
@@ -2273,6 +2461,34 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
 #endif
          }
       return;
+
+    case SOLVER_LOCK:
+      if (!installed)
+       break;
+      qstart = q->count;
+      if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+       {
+         FOR_REPO_SOLVABLES(installed, p, s)
+           {
+             for (i = qstart; i < q->count; i += 2)
+               if (q->elements[i] == DISABLE_DUP && q->elements[i + 1] == pool->solvables[p].name)
+                 break;
+             if (i == q->count)
+               queue_push2(q, DISABLE_DUP, pool->solvables[p].name);
+           }
+       }
+      FOR_JOB_SELECT(p, pp, select, what)
+       {
+         if (pool->solvables[p].repo != installed)
+           continue;
+         for (i = qstart; i < q->count; i += 2)
+           if (q->elements[i] == DISABLE_DUP && q->elements[i + 1] == pool->solvables[p].name)
+             break;
+         if (i == q->count)
+           queue_push2(q, DISABLE_DUP, pool->solvables[p].name);
+       }
+      break;
+
     default:
       return;
     }
@@ -2324,6 +2540,9 @@ solver_disablepolicyrules(Solver *solv)
        case DISABLE_DUP:
          disableduprule(solv, arg);
          break;
+       case DISABLE_BLACK:
+         disableblackrule(solv, arg);
+         break;
        default:
          break;
        }
@@ -2427,6 +2646,9 @@ solver_reenablepolicyrules(Solver *solv, int jobidx)
        case DISABLE_DUP:
          reenableduprule(solv, arg);
          break;
+       case DISABLE_BLACK:
+         reenableblackrule(solv, arg);
+         break;
        }
     }
   queue_free(&q);
@@ -2753,6 +2975,12 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
        *depp = solv->yumobsrules_info[rid - solv->yumobsrules];
       return SOLVER_RULE_YUMOBS;
     }
+  if (rid >= solv->blackrules && rid < solv->blackrules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      return SOLVER_RULE_BLACK;
+    }
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     return SOLVER_RULE_CHOICE;
   if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
@@ -2783,10 +3011,14 @@ solver_ruleclass(Solver *solv, Id rid)
     return SOLVER_RULE_BEST;
   if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
     return SOLVER_RULE_YUMOBS;
+  if (rid >= solv->blackrules && rid < solv->blackrules_end)
+    return SOLVER_RULE_BLACK;
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     return SOLVER_RULE_CHOICE;
   if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
     return SOLVER_RULE_RECOMMENDS;
+  if (rid >= solv->blackrules && rid < solv->blackrules_end)
+    return SOLVER_RULE_BLACK;
   if (rid >= solv->learntrules && rid < solv->nrules)
     return SOLVER_RULE_LEARNT;
   return SOLVER_RULE_UNKNOWN;
@@ -3260,8 +3492,34 @@ prune_to_dup_packages(Solver *solv, Id p, Queue *q)
   queue_truncate(q, j);
 }
 
+static void
+prune_best_update(Solver *solv, Id p, Queue *q)
+{
+  if (solv->update_targets && solv->update_targets->elements[p - solv->installed->start])
+    prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - solv->installed->start], q);
+  if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+    prune_to_dup_packages(solv, p, q);
+  /* select best packages, just look at prio and version */
+  policy_filter_unwanted(solv, q, POLICY_MODE_RECOMMEND);
+}
+
+static void
+prune_disabled(Pool *pool, Queue *q)
+{
+  int i, j;
+  for (i = j = 0; i < q->count; i++)
+    {
+      Id p = q->elements[i];
+      Solvable *s = pool->solvables + p;
+      if (s->repo && s->repo != pool->installed && !MAPTST(pool->considered, p))
+       continue;
+      q->elements[j++] = p;
+    }
+  queue_truncate(q, j);
+}
+
 void
-solver_addbestrules(Solver *solv, int havebestinstalljobs)
+solver_addbestrules(Solver *solv, int havebestinstalljobs, int haslockjob)
 {
   Pool *pool = solv->pool;
   Id p;
@@ -3271,12 +3529,26 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
   Rule *r;
   Queue infoq;
   int i, oldcnt;
+  Map *lockedmap = 0;
 
   solv->bestrules = solv->nrules;
   queue_init(&q);
   queue_init(&q2);
   queue_init(&infoq);
 
+  if (haslockjob)
+    {
+      int i;
+      lockedmap = solv_calloc(1, sizeof(Map));
+      map_init(lockedmap, pool->nsolvables);
+      for (i = 0, r = solv->rules + solv->jobrules; i < solv->ruletojob.count; i++, r++)
+       {
+         if (r->w2 || (solv->job.elements[solv->ruletojob.elements[i]] & SOLVER_JOBMASK) != SOLVER_LOCK)
+           continue;
+         p = r->p > 0 ? r->p : -r->p;
+         MAPSET(lockedmap, p);
+       }
+    }
   if (havebestinstalljobs)
     {
       for (i = 0; i < solv->job.count; i += 2)
@@ -3284,7 +3556,7 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
          Id how = solv->job.elements[i];
          if ((how & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
            {
-             int j;
+             int j, k;
              Id p2, pp2;
              for (j = 0; j < solv->ruletojob.count; j++)
                {
@@ -3300,6 +3572,8 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
                      else if (p2 < 0)
                        queue_push(&q2, p2);
                    }
+                 if (pool->considered && pool->whatprovideswithdisabled)
+                   prune_disabled(pool, &q);
                  if (!q.count)
                    continue;   /* orphaned */
                  /* select best packages, just look at prio and version */
@@ -3307,6 +3581,30 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
                  policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
                  if (q.count == oldcnt)
                    continue;   /* nothing filtered */
+                 if (lockedmap)
+                   {
+                     queue_insertn(&q, 0, q2.count, q2.elements);
+                     queue_empty(&q2);
+                     FOR_RULELITERALS(p2, pp2, r)
+                       {
+                         if (p2 <= 0)
+                           continue;
+                         if (installed && pool->solvables[p2].repo == installed)
+                           {
+                             if (MAPTST(lockedmap, p2))
+                               queue_pushunique(&q, p2);               /* we always want that package */
+                           }
+                         else if (MAPTST(lockedmap, p2))
+                           continue;
+                         queue_push(&q2, p2);
+                       }
+                     if (pool->considered && pool->whatprovideswithdisabled)
+                       prune_disabled(pool, &q2);
+                     policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND);
+                     for (k = 0; k < q2.count; k++)
+                       queue_pushunique(&q, q2.elements[k]);
+                     queue_empty(&q2);
+                   }
                  if (q2.count)
                    queue_insertn(&q, 0, q2.count, q2.elements);
                  p2 = queue_shift(&q);
@@ -3361,14 +3659,38 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
                if (p2 > 0)
                  queue_push(&q, p2);
            }
-         if (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);
-         if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
-           prune_to_dup_packages(solv, p, &q);
-         /* select best packages, just look at prio and version */
-         policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+         if (lockedmap)
+           {
+             queue_empty(&q2);
+             queue_insertn(&q2, 0, q.count, q.elements);
+           }
+         prune_best_update(solv, p, &q);
          if (!q.count)
            continue;   /* orphaned */
+         if (lockedmap)
+           {
+             int j;
+             /* always ok to keep installed locked packages */
+             if (MAPTST(lockedmap, p))
+               queue_pushunique(&q2, p);
+             for (j = 0; j < q2.count; j++)
+               {
+                 Id p2 = q2.elements[j];
+                 if (pool->solvables[p2].repo == installed && MAPTST(lockedmap, p2))
+                   queue_pushunique(&q, p2);
+               }
+             /* filter out locked packages */
+             for (i = j = 0; j < q2.count; j++)
+               {
+                 Id p2 = q2.elements[j];
+                 if (pool->solvables[p2].repo == installed || !MAPTST(lockedmap, p2))
+                   q2.elements[i++] = p2;
+               }
+             queue_truncate(&q2, i);
+             prune_best_update(solv, p, &q2);
+             for (j = 0; j < q2.count; j++)
+               queue_pushunique(&q, q2.elements[j]);
+           }
          if (solv->bestobeypolicy)
            {
              /* also filter the best of the feature rule packages and add them */
@@ -3380,13 +3702,20 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
                  FOR_RULELITERALS(p2, pp2, r)
                    if (p2 > 0)
                      queue_push(&q2, p2);
-                 if (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], &q2);
-                 if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
-                   prune_to_dup_packages(solv, p, &q2);
-                 policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND);
+                 prune_best_update(solv, p, &q2);
                  for (j = 0; j < q2.count; j++)
                    queue_pushunique(&q, q2.elements[j]);
+                 if (lockedmap)
+                   {
+                     queue_empty(&q2);
+                     FOR_RULELITERALS(p2, pp2, r)
+                       if (p2 > 0)
+                         if (pool->solvables[p2].repo == installed || !MAPTST(lockedmap, p2))
+                           queue_push(&q2, p2);
+                     prune_best_update(solv, p, &q2);
+                     for (j = 0; j < q2.count; j++)
+                       queue_pushunique(&q, q2.elements[j]);
+                   }
                }
            }
          if (solv->allowuninstall || solv->allowuninstall_all || (solv->allowuninstallmap.size && MAPTST(&solv->allowuninstallmap, p - installed->start)))
@@ -3427,6 +3756,11 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
   queue_free(&q);
   queue_free(&q2);
   queue_free(&infoq);
+  if (lockedmap)
+    {
+      map_free(lockedmap);
+      solv_free(lockedmap);
+    }
 }