}
static int
-sort_by_favorq_cmp(const void *ap, const void *bp, void *dp)
+sort_by_favor_cmp(const void *ap, const void *bp, void *dp)
{
const Id *a = ap, *b = bp, *d = dp;
return d[b[0]] - d[a[0]];
}
-static void
-sort_by_favorq(Queue *favorq, Id *el, int cnt)
-{
- int i;
- /* map to offsets into favorq */
- for (i = 0; i < cnt; i++)
- {
- Id p = el[i];
- /* lookup p in sorted favorq */
- int med = 0, low = 0;
- int high = favorq->count / 2;
- while (low != high)
- {
- med = (low + high) / 2;
- Id pp = favorq->elements[2 * med];
- if (pp < p)
- low = med;
- else if (pp > p)
- high = med;
- else
- break;
- }
- while(med && favorq->elements[2 * med - 2] == p)
- med--;
- if (favorq->elements[2 * med] == p)
- el[i] = 2 * med + 1;
- else
- el[i] = 0; /* hmm */
- }
- /* sort by position */
- solv_sort(el, cnt, sizeof(Id), sort_by_favorq_cmp, favorq->elements);
- /* map back */
- for (i = 0; i < cnt; i++)
- if (el[i])
- el[i] = favorq->elements[el[i] - 1];
-}
-
/* bring favored packages to front and disfavored packages to back */
void
policy_prefer_favored(Solver *solv, Queue *plist)
{
- int i, fav, disfav, count;
- if (!solv->favormap.size)
- return;
- for (i = fav = disfav = 0, count = plist->count; i < count; i++)
- {
- Id p = plist->elements[i];
- if (!MAPTST(&solv->favormap, p))
- continue;
- if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))
- {
- /* disfavored package. bring to back */
- if (i < plist->count - 1)
- {
- memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
- plist->elements[plist->count - 1] = p;
- }
- i--;
- count--;
- disfav++;
- }
- else
- {
- /* favored package. bring to front */
- if (i > fav)
- memmove(plist->elements + fav + 1, plist->elements + fav, (i - fav) * sizeof(Id));
- plist->elements[fav++] = p;
- }
- }
- /* if we have multiple favored/disfavored packages, sort by favorq index */
- if (fav > 1)
- sort_by_favorq(solv->favorq, plist->elements, fav);
- if (disfav > 1)
- sort_by_favorq(solv->favorq, plist->elements + plist->count - disfav, disfav);
+ if (solv->favormap && plist->count > 1)
+ solv_sort(plist->elements, plist->count, sizeof(Id), sort_by_favor_cmp, solv->favormap);
}
/*
queue_truncate(plist, count);
}
+/* support multiple favor groups by calling policy_filter_unwanted on
+ * each of them and combining the result */
+static void
+policy_filter_unwanted_favored(Solver *solv, Queue *plist, int mode)
+{
+ int i, j, f;
+ Queue qin, qprune;
+ queue_init_clone(&qin, plist);
+ queue_empty(plist);
+ /* sort by favor group */
+ solv_sort(qin.elements, qin.count, sizeof(Id), sort_by_favor_cmp, solv->favormap);
+ /* go over groups */
+ queue_init(&qprune);
+ for (i = 0; i < qin.count; i = j)
+ {
+ /* find end of group */
+ f = solv->favormap[qin.elements[i]];
+ for (j = i + 1; j < qin.count; j++)
+ if (solv->favormap[qin.elements[j]] != f)
+ break;
+ /* prune this group */
+ queue_empty(&qprune);
+ queue_insertn(&qprune, 0, j, qin.elements);
+ policy_filter_unwanted(solv, &qprune, mode | POLICY_MODE_FAVOR_REC);
+ for (i = 0; i < qprune.count; i++)
+ if (solv->favormap[qprune.elements[i]] == f)
+ queue_push(plist, qprune.elements[i]);
+ }
+ queue_free(&qprune);
+ queue_free(&qin);
+}
/*
* POLICY_MODE_CHOOSE: default, do all pruning steps
policy_prefer_favored(solv, plist);
return;
}
+ if (mode & POLICY_MODE_FAVOR_REC)
+ mode ^= POLICY_MODE_FAVOR_REC;
+ else if (solv->favormap && plist->count > 1)
+ {
+ /* check if we have multiple favor groups */
+ int i, f = solv->favormap[plist->elements[0]];
+ for (i = 1; i < plist->count; i++)
+ if (solv->favormap[plist->elements[i]] != f)
+ break;
+ if (i < plist->count)
+ {
+ policy_filter_unwanted_favored(solv, plist, mode);
+ return;
+ }
+ }
if (plist->count > 1)
{
if (mode != POLICY_MODE_SUGGEST)
#define POLICY_MODE_SUGGEST 2
#define POLICY_MODE_CHOOSE_NOREORDER 3 /* internal, do not use */
#define POLICY_MODE_SUPPLEMENT 4 /* internal, do not use */
+#define POLICY_MODE_FAVOR_REC (1 << 30) /* internal, do not use */
#define POLICY_ILLEGAL_DOWNGRADE 1
continue;
if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */
continue;
-
+
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
solver_recordproblem(solv, i);
map_free(&solv->droporphanedmap);
map_free(&solv->cleandepsmap);
map_free(&solv->allowuninstallmap);
- map_free(&solv->favormap);
- map_free(&solv->isdisfavormap);
+ solv_free(solv->favormap);
solv_free(solv->decisionmap);
solv_free(solv->rules);
solv_free(solv->watches);
prune_disfavored(Solver *solv, Queue *plist)
{
int i, j;
- if (!solv->isdisfavormap.size)
- return;
- for (i = j = 0; i < plist->count; i++)
- {
+ for (i = j = 0; i < plist->count; i++)
+ {
Id p = plist->elements[i];
- if (!MAPTST(&solv->isdisfavormap, p))
- plist->elements[j++] = p;
- }
+ if (solv->favormap[p] >= 0)
+ plist->elements[j++] = p;
+ }
if (i != j)
queue_truncate(plist, j);
}
continue;
if (solv->process_orphans && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
continue;
- if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, i))
+ if (solv->havedisfavored && solv->favormap[i] < 0)
continue; /* disfavored supplements, do not install */
queue_push(dqs, i);
}
}
/* filter out disfavored recommended packages */
- if (dq->count && solv->isdisfavormap.size)
+ if (dq->count && solv->havedisfavored)
prune_disfavored(solv, dq);
/* filter out all packages obsoleted by installed packages */
if (rerun)
continue;
}
-
+
/* one final pass to make sure we decided all installed packages */
if (solv->installed)
{
lastsi = -1;
break;
}
- if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))
+ if (solv->havedisfavored && solv->favormap[p] < 0)
continue;
if (lastsi < 0 && (MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
lastsi = i;
p = -solv->branches.elements[i];
if (p <= 0 || solv->decisionmap[p] != l + 1)
continue;
- if (solv->favormap.size && MAPTST(&solv->favormap, p))
- if (!(solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p)))
- continue; /* current selection is favored */
+ if (solv->favormap && solv->favormap[p] > solv->favormap[solv->branches.elements[lastsi]])
+ continue; /* current selection is more favored */
if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
{
lasti = lastsi;
/* sort by package id, last entry wins */
static int
-setup_favormaps_cmp(const void *ap, const void *bp, void *dp)
+setup_favormap_cmp(const void *ap, const void *bp, void *dp)
{
const Id *a = ap, *b = bp;
if ((*a - *b) != 0)
}
static void
-setup_favormaps(Solver *solv)
+setup_favormap(Solver *solv)
{
Queue *q = solv->favorq;
Pool *pool = solv->pool;
int i;
Id oldp = 0;
if (q->count > 2)
- solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormaps_cmp, solv);
- map_grow(&solv->favormap, pool->nsolvables);
+ solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormap_cmp, solv);
+ solv->favormap = solv_calloc(pool->nsolvables, sizeof(Id));
+ solv->havedisfavored = 0;
for (i = 0; i < q->count; i += 2)
{
Id p = q->elements[i];
if (p == oldp)
continue;
oldp = p;
- MAPSET(&solv->favormap, p);
+ solv->favormap[p] = q->elements[i + 1];
if (q->elements[i + 1] < 0)
- {
- if (!solv->isdisfavormap.size)
- map_grow(&solv->isdisfavormap, pool->nsolvables);
- MAPSET(&solv->isdisfavormap, p);
- }
+ solv->havedisfavored = 1;
}
}
map_zerosize(&solv->allowuninstallmap);
map_zerosize(&solv->cleandepsmap);
map_zerosize(&solv->weakrulemap);
- map_zerosize(&solv->favormap);
- map_zerosize(&solv->isdisfavormap);
+ solv->favormap = solv_free(solv->favormap);
queue_empty(&solv->weakruleq);
solv->watches = solv_free(solv->watches);
queue_empty(&solv->ruletojob);
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)
{
- int j;
if (!solv->favorq)
{
solv->favorq = solv_calloc(1, sizeof(Queue));
queue_init(solv->favorq);
}
- j = solv->favorq->count + 1;
- queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? j : -j);
+ queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? i + 1 : -(i + 1));
}
break;
default:
assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
solv->jobrules_end = solv->nrules;
- /* transform favorq into two maps */
+ /* sort favorq and transform it into two maps */
if (solv->favorq)
- setup_favormaps(solv);
+ setup_favormap(solv);
/* now create infarch and dup rules */
if (!solv->noinfarchcheck)
int allowuninstall_all;
Queue *favorq;
- Map favormap; /* favored / disfavored packages */
- Map isdisfavormap;
+ Id *favormap; /* favor job index, > 0: favored, < 0: disfavored */
+ int havedisfavored; /* do we have disfavored packages? */
int installedpos; /* for resolve_installed */
int do_extra_reordering; /* reorder for future installed packages */
--- /dev/null
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: a 1 1 noarch
+#>=Req: b
+#>=Rec: b1
+#>=Pkg: b1 1 1 noarch
+#>=Prv: b
+#>=Pkg: b2 1 1 noarch
+#>=Prv: b
+system x86_64 rpm system
+poolflags implicitobsoleteusescolors
+solverflags ignorerecommended
+job install pkg a-1-1.noarch@available
+job favor name b2
+result transaction,problems,alternatives <inline>
+#>alternative 64eb4d87 0 a-1-1.noarch@available requires b
+#>alternative 64eb4d87 1 + b2-1-1.noarch@available
+#>alternative 64eb4d87 2 b1-1-1.noarch@available
+#>install a-1-1.noarch@available
+#>install b2-1-1.noarch@available
--- /dev/null
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: gcc 5 1 noarch
+#>=Prv: gcc
+#>=Pkg: gcc 6 1 noarch
+#>=Prv: gcc
+#>=Pkg: build-tools 1 1 noarch
+#>=Req: gcc
+system unset * system
+
+job install name build-tools
+job favor pkg gcc-5-1.noarch@available
+result transaction,problems,alternatives <inline>
+#>alternative 6e50ec1a 0 build-tools-1-1.noarch@available requires gcc
+#>alternative 6e50ec1a 1 + gcc-5-1.noarch@available
+#>alternative 6e50ec1a 2 gcc-6-1.noarch@available
+#>install build-tools-1-1.noarch@available
+#>install gcc-5-1.noarch@available
+
+nextjob
+
+job install name build-tools
+job disfavor pkg gcc-6-1.noarch@available
+result transaction,problems,alternatives <inline>
+#>alternative 6e50ec1a 0 build-tools-1-1.noarch@available requires gcc
+#>alternative 6e50ec1a 1 + gcc-5-1.noarch@available
+#>alternative 6e50ec1a 2 gcc-6-1.noarch@available
+#>install build-tools-1-1.noarch@available
+#>install gcc-5-1.noarch@available
+