diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2018-11-30 12:38:58 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2018-11-30 12:39:53 +0900 |
commit | 22e701e553344eeb22f88ed0906d76c9a5e39d83 (patch) | |
tree | 493781d54b4af93dc853e86a0be040d1da95a13c /src | |
parent | f458102388250c8a1cbbfa8f18d27baa204c696c (diff) | |
download | libsolv-22e701e553344eeb22f88ed0906d76c9a5e39d83.tar.gz libsolv-22e701e553344eeb22f88ed0906d76c9a5e39d83.tar.bz2 libsolv-22e701e553344eeb22f88ed0906d76c9a5e39d83.zip |
Imported Upstream version 0.6.24upstream/0.6.24
Change-Id: I68f4d40b704c1ccd2a86576a3c03687922f023aa
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/order.c | 6 | ||||
-rw-r--r-- | src/problems.c | 30 | ||||
-rw-r--r-- | src/rules.c | 12 | ||||
-rw-r--r-- | src/selection.c | 34 | ||||
-rw-r--r-- | src/solver.c | 1608 | ||||
-rw-r--r-- | src/solver.h | 13 | ||||
-rw-r--r-- | src/solvversion.h.in | 1 |
7 files changed, 877 insertions, 827 deletions
diff --git a/src/order.c b/src/order.c index d560865..4fe3e08 100644 --- a/src/order.c +++ b/src/order.c @@ -1262,8 +1262,10 @@ transaction_check_order(Transaction *trans) map_init(&ins, pool->nsolvables); map_init(&seen, pool->nsolvables); if (pool->installed) - FOR_REPO_SOLVABLES(pool->installed, p, s) - MAPSET(&ins, p); + { + FOR_REPO_SOLVABLES(pool->installed, p, s) + MAPSET(&ins, p); + } lastins = 0; for (i = 0; i < trans->steps.count; i++) { diff --git a/src/problems.c b/src/problems.c index b57d980..063d47b 100644 --- a/src/problems.c +++ b/src/problems.c @@ -588,17 +588,12 @@ create_solutions(Solver *solv, int probnr, int solidx) { Pool *pool = solv->pool; Queue redoq; - Queue problem, solution, problems_save, branches_save; + Queue problem, solution, problems_save, branches_save, decisionq_reason_save; int i, j, nsol; int essentialok; unsigned int now; int oldmistakes = solv->cleandeps_mistakes ? solv->cleandeps_mistakes->count : 0; Id extraflags = -1; - int decisioncnt_update; - int decisioncnt_keep; - int decisioncnt_resolve; - int decisioncnt_weak; - int decisioncnt_orphan; now = solv_timems(0); queue_init(&redoq); @@ -610,11 +605,6 @@ create_solutions(Solver *solv, int probnr, int solidx) queue_push(&redoq, solv->decisionq_why.elements[i]); queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]); } - decisioncnt_update = solv->decisioncnt_update; - decisioncnt_keep = solv->decisioncnt_keep; - decisioncnt_resolve = solv->decisioncnt_resolve; - decisioncnt_weak = solv->decisioncnt_weak; - decisioncnt_orphan = solv->decisioncnt_orphan; /* save problems queue */ problems_save = solv->problems; @@ -624,6 +614,10 @@ create_solutions(Solver *solv, int probnr, int solidx) branches_save = solv->problems; memset(&solv->branches, 0, sizeof(solv->branches)); + /* save decisionq_reason */ + decisionq_reason_save = solv->decisionq_reason; + memset(&solv->decisionq_reason, 0, sizeof(solv->decisionq_reason)); + /* extract problem from queue */ queue_init(&problem); for (i = solidx + 1; i < solv->solutions.count; i++) @@ -711,11 +705,10 @@ create_solutions(Solver *solv, int probnr, int solidx) solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2]; } queue_free(&redoq); - solv->decisioncnt_update = decisioncnt_update; - solv->decisioncnt_keep = decisioncnt_keep; - solv->decisioncnt_resolve = decisioncnt_resolve; - solv->decisioncnt_weak = decisioncnt_weak; - solv->decisioncnt_orphan = decisioncnt_orphan; + + /* restore decision reasons */ + queue_free(&solv->decisionq_reason); + solv->decisionq_reason = decisionq_reason_save; /* restore problems */ queue_free(&solv->problems); @@ -962,8 +955,11 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, { if (*reqrp > 0 && r->p < -1) { + Pool *pool = solv->pool; Id op = -solv->rules[*reqrp].p; - if (op > 1 && solv->pool->solvables[op].arch != solv->pool->solvables[-r->p].arch) + if (op > 1 && pool->solvables[op].arch != pool->solvables[-r->p].arch && + pool->solvables[op].arch != pool->noarchid && + pool->solvables[-r->p].arch != pool->noarchid) continue; /* different arch, skip */ } /* prefer assertions */ diff --git a/src/rules.c b/src/rules.c index aa90b5f..67f10d8 100644 --- a/src/rules.c +++ b/src/rules.c @@ -2361,8 +2361,10 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) if (!installed) break; if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) - FOR_REPO_SOLVABLES(installed, p, s) - queue_push2(q, DISABLE_UPDATE, p); + { + FOR_REPO_SOLVABLES(installed, p, s) + queue_push2(q, DISABLE_UPDATE, p); + } FOR_JOB_SELECT(p, pp, select, what) if (pool->solvables[p].repo == installed) { @@ -3956,8 +3958,10 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) what = job->elements[i + 1]; select = how & SOLVER_SELECTMASK; if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) - FOR_REPO_SOLVABLES(installed, p, s) - MAPSET(&userinstalled, p - installed->start); + { + FOR_REPO_SOLVABLES(installed, p, s) + MAPSET(&userinstalled, p - installed->start); + } FOR_JOB_SELECT(p, pp, select, what) if (pool->solvables[p].repo == installed) MAPSET(&userinstalled, p - installed->start); diff --git a/src/selection.c b/src/selection.c index 6b89ab0..37c6184 100644 --- a/src/selection.c +++ b/src/selection.c @@ -53,8 +53,10 @@ selection_prune(Pool *pool, Queue *selection) Solvable *s; Repo *repo = pool_id2repo(pool, selection->elements[i + 1]); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - break; + { + FOR_REPO_SOLVABLES(repo, p, s) + break; + } } else { @@ -96,8 +98,10 @@ selection_solvables(Pool *pool, Queue *selection, Queue *pkgs) Solvable *s; Repo *repo = pool_id2repo(pool, selection->elements[i + 1]); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - queue_push(pkgs, p); + { + FOR_REPO_SOLVABLES(repo, p, s) + queue_push(pkgs, p); + } } else { @@ -1100,8 +1104,10 @@ selection_filter(Pool *pool, Queue *sel1, Queue *sel2) Solvable *s; Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - map_set(&m2, p); + { + FOR_REPO_SOLVABLES(repo, p, s) + map_set(&m2, p); + } } else { @@ -1163,13 +1169,15 @@ selection_filter(Pool *pool, Queue *sel1, Queue *sel2) Solvable *s; Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - { - if (map_tst(&m2, p)) - queue_push(&q1, p); - else - miss = 1; - } + { + FOR_REPO_SOLVABLES(repo, p, s) + { + if (map_tst(&m2, p)) + queue_push(&q1, p); + else + miss = 1; + } + } } else { diff --git a/src/solver.c b/src/solver.c index 5fca20d..efe3342 100644 --- a/src/solver.c +++ b/src/solver.c @@ -341,6 +341,7 @@ makeruledecisions(Solver *solv) assert(solv->decisionq.count == 0); queue_push(&solv->decisionq, SYSTEMSOLVABLE); queue_push(&solv->decisionq_why, 0); + queue_push2(&solv->decisionq_reason, 0, 0); solv->decisionmap[SYSTEMSOLVABLE] = 1; /* installed at level '1' */ decisionstart = solv->decisionq.count; @@ -907,18 +908,7 @@ revert(Solver *solv, int level) solv->branches.count -= solv->branches.elements[solv->branches.count - 2]; if (solv->recommends_index > solv->decisionq.count) solv->recommends_index = -1; /* rebuild recommends/suggests maps */ - if (solv->decisionq.count < solv->decisioncnt_jobs) - solv->decisioncnt_jobs = 0; - if (solv->decisionq.count < solv->decisioncnt_update) - solv->decisioncnt_update = 0; - if (solv->decisionq.count < solv->decisioncnt_keep) - solv->decisioncnt_keep = 0; - if (solv->decisionq.count < solv->decisioncnt_resolve) - solv->decisioncnt_resolve = 0; - if (solv->decisionq.count < solv->decisioncnt_weak) - solv->decisioncnt_weak= 0; - if (solv->decisionq.count < solv->decisioncnt_orphan) - solv->decisioncnt_orphan = 0; + solv->decisionq_reason.count = level + 1; } /*------------------------------------------------------------------- @@ -1111,9 +1101,9 @@ solver_reset(Solver *solv) } queue_empty(&solv->decisionq_why); queue_empty(&solv->decisionq); + queue_empty(&solv->decisionq_reason); solv->recommends_index = -1; solv->propagate_index = 0; - solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; queue_empty(&solv->branches); /* adapt learnt rule status to new set of enabled/disabled rules */ @@ -1334,7 +1324,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) */ static int -setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid) +setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid, Id reason) { Pool *pool = solv->pool; Rule *r, *lr; @@ -1348,6 +1338,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul solv->decisionmap[-decision] = -level; queue_push(&solv->decisionq, decision); queue_push(&solv->decisionq_why, -ruleid); /* <= 0 -> free decision */ + queue_push(&solv->decisionq_reason, reason); } assert(ruleid >= 0 && level > 0); for (;;) @@ -1376,7 +1367,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul } static void -reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq) +reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq) { Pool *pool = solv->pool; int i, j, haveone = 0, dqcount = dq->count; @@ -1464,7 +1455,7 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) { Pool *pool = solv->pool; int level; - Id p, why; + Id p, why, reason; #if 0 { int i; @@ -1484,7 +1475,8 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) /* hack: revert simply sets the count, so we can still access the reverted elements */ why = -solv->decisionq_why.elements[solv->decisionq_why.count]; assert(why >= 0); - return setpropagatelearn(solv, level, p, disablerules, why); + reason = solv->decisionq_reason.elements[level + 1]; + return setpropagatelearn(solv, level, p, disablerules, why, reason); } /*------------------------------------------------------------------- @@ -1499,23 +1491,23 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) */ static int -selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid) +selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid, Id reason) { Pool *pool = solv->pool; Id p; if (dq->count > 1) policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); - /* if we're resolving job rules and didn't resolve the installed packages yet, + /* if we're resolving rules and didn't resolve the installed packages yet, * do some special supplements ordering */ - if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed && !solv->focus_installed) - reorder_dq_for_jobrules(solv, level, dq); + if (dq->count > 1 && solv->do_extra_reordering) + reorder_dq_for_future_installed(solv, level, dq); /* if we have multiple candidates we open a branch */ if (dq->count > 1) createbranch(solv, level, dq, 0, ruleid); p = dq->elements[0]; POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p)); - return setpropagatelearn(solv, level, p, disablerules, ruleid); + return setpropagatelearn(solv, level, p, disablerules, ruleid, reason); } @@ -1556,6 +1548,7 @@ solver_create(Pool *pool) queue_init(&solv->ruletojob); queue_init(&solv->decisionq); queue_init(&solv->decisionq_why); + queue_init(&solv->decisionq_reason); queue_init(&solv->problems); queue_init(&solv->orphaned); queue_init(&solv->learnt_why); @@ -1581,80 +1574,6 @@ solver_create(Pool *pool) } -static int -resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq) -{ - Pool *pool = solv->pool; - int oldlevel = level; - int i, olevel; - Rule *r; - - POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); - if (!solv->decisioncnt_jobs) - solv->decisioncnt_jobs = solv->decisionq.count; - for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) - { - Id l, pp; - if (r->d < 0) /* ignore disabled rules */ - continue; - queue_empty(dq); - FOR_RULELITERALS(l, pp, r) - { - if (l < 0) - { - if (solv->decisionmap[-l] <= 0) - break; - } - else - { - if (solv->decisionmap[l] > 0) - break; - if (solv->decisionmap[l] == 0) - queue_push(dq, l); - } - } - if (l || !dq->count) - continue; - /* prune to installed if not updating */ - if (dq->count > 1 && solv->installed && !solv->updatemap_all && - !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) - { - int j, k; - for (j = k = 0; j < dq->count; j++) - { - Solvable *s = pool->solvables + dq->elements[j]; - if (s->repo == solv->installed) - { - dq->elements[k++] = dq->elements[j]; - if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start)) - { - k = 0; /* package wants to be updated, do not prune */ - break; - } - } - } - if (k) - dq->count = k; - } - olevel = level; - level = selectandinstall(solv, level, dq, disablerules, i); - if (level <= olevel) - { - if (level == olevel) - { - i--; - r--; - continue; /* try something else */ - } - if (level < oldlevel) - return level; - /* redo from start of jobrules */ - i = solv->jobrules - 1; - r = solv->rules + i; - } - } - return level; -} /*------------------------------------------------------------------- * @@ -1687,6 +1606,7 @@ solver_free(Solver *solv) queue_free(&solv->ruletojob); queue_free(&solv->decisionq); queue_free(&solv->decisionq_why); + queue_free(&solv->decisionq_reason); queue_free(&solv->learnt_why); queue_free(&solv->learnt_pool); queue_free(&solv->problems); @@ -1780,6 +1700,8 @@ solver_get_flag(Solver *solv, int flag) return solv->break_orphans; case SOLVER_FLAG_FOCUS_INSTALLED: return solv->focus_installed; + case SOLVER_FLAG_FOCUS_BEST: + return solv->focus_best; case SOLVER_FLAG_YUM_OBSOLETES: return solv->do_yum_obsoletes; case SOLVER_FLAG_NEED_UPDATEPROVIDE: @@ -1858,6 +1780,9 @@ solver_set_flag(Solver *solv, int flag, int value) case SOLVER_FLAG_FOCUS_INSTALLED: solv->focus_installed = value; break; + case SOLVER_FLAG_FOCUS_BEST: + solv->focus_best = value; + break; case SOLVER_FLAG_YUM_OBSOLETES: solv->do_yum_obsoletes = value; break; @@ -1874,6 +1799,79 @@ solver_set_flag(Solver *solv, int flag, int value) } static int +resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + int oldlevel = level; + int i, olevel; + Rule *r; + + POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); + for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) + { + Id l, pp; + if (r->d < 0) /* ignore disabled rules */ + continue; + queue_empty(dq); + FOR_RULELITERALS(l, pp, r) + { + if (l < 0) + { + if (solv->decisionmap[-l] <= 0) + break; + } + else + { + if (solv->decisionmap[l] > 0) + break; + if (solv->decisionmap[l] == 0) + queue_push(dq, l); + } + } + if (l || !dq->count) + continue; + /* prune to installed if not updating */ + if (dq->count > 1 && solv->installed && !solv->updatemap_all && + !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) + { + int j, k; + for (j = k = 0; j < dq->count; j++) + { + Solvable *s = pool->solvables + dq->elements[j]; + if (s->repo == solv->installed) + { + dq->elements[k++] = dq->elements[j]; + if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start)) + { + k = 0; /* package wants to be updated, do not prune */ + break; + } + } + } + if (k) + dq->count = k; + } + olevel = level; + level = selectandinstall(solv, level, dq, disablerules, i, SOLVER_REASON_RESOLVE_JOB); + if (level <= olevel) + { + if (level == olevel) + { + i--; + r--; + continue; /* try something else */ + } + if (level < oldlevel) + return level; + /* redo from start of jobrules */ + i = solv->jobrules - 1; + r = solv->rules + i; + } + } + return level; +} + +static int cleandeps_check_mistakes(Solver *solv) { Pool *pool = solv->pool; @@ -1941,6 +1939,291 @@ prune_to_update_targets(Solver *solv, Id *cp, Queue *q) queue_truncate(q, j); } +static int +resolve_installed(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + int i, n, pass; + int installedpos = solv->installedpos; + Solvable *s; + Id p, pp; + int olevel, origlevel = level; + + POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n"); + if (!installedpos) + installedpos = installed->start; + /* we use two passes if we need to update packages + * to create a better user experience */ + for (pass = solv->updatemap.size ? 0 : 1; pass < 2; ) + { + int passlevel = level; + Id *specialupdaters = solv->specialupdaters; + /* start with installedpos, the position that gave us problems the last time */ + for (i = installedpos, n = installed->start; n < installed->end; i++, n++) + { + Rule *r, *rr; + Id d; + + if (i == installed->end) + i = installed->start; + s = pool->solvables + i; + if (s->repo != installed) + continue; + + if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start])) + continue; /* already decided */ + if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start)) + continue; /* updates first */ + r = solv->rules + solv->updaterules + (i - installed->start); + rr = r; + if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */ + rr -= solv->installed->end - solv->installed->start; + if (!rr->p) /* identical to update rule? */ + rr = r; + if (!rr->p) + continue; /* orpaned package or pseudo package */ + + /* check if we should update this package to the latest version + * noupdate is set for erase jobs, in that case we want to deinstall + * the installed package and not replace it with a newer version + * rr->p != i is for dup jobs where the installed package cannot be kept */ + if (dq->count) + queue_empty(dq); + if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i))) + { + if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0) + { + /* 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); + 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) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + p = dq->elements[0]; + if (p != i && solv->decisionmap[p] == 0) + { + rr = solv->rules + solv->featurerules + (i - solv->installed->start); + if (!rr->p) /* update rule == feature rule? */ + rr = rr - solv->featurerules + solv->updaterules; + dq->count = 1; + } + else + dq->count = 0; + } + } + else + { + /* update to best package of the update rule */ + FOR_RULELITERALS(p, pp, rr) + { + if (solv->decisionmap[p] > 0) + { + dq->count = 0; /* already fulfilled */ + break; + } + if (!solv->decisionmap[p]) + queue_push(dq, p); + } + } + } + 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); + /* install best version */ + if (dq->count) + { + olevel = level; + level = selectandinstall(solv, level, dq, disablerules, rr - solv->rules, SOLVER_REASON_UPDATE_INSTALLED); + if (level <= olevel) + { + if (level < passlevel) + break; /* trouble */ + if (level < olevel) + n = installed->start; /* redo all */ + i--; + n--; + continue; + } + } + /* if still undecided keep package */ + if (solv->decisionmap[i] == 0) + { + olevel = level; + if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start)) + { +#if 0 + POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i)); + level = setpropagatelearn(solv, level, -i, disablerules, 0, SOLVER_REASON_CLEANDEPS_ERASE); +#else + continue; +#endif + } + else + { + POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i)); + level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules, SOLVER_REASON_KEEP_INSTALLED); + } + if (level <= olevel) + { + if (level < passlevel) + break; /* trouble */ + if (level < olevel) + n = installed->start; /* redo all */ + i--; + n--; + continue; /* retry with learnt rule */ + } + } + } + if (n < installed->end) + { + installedpos = i; /* retry problem solvable next time */ + if (level < origlevel) + break; /* ran into trouble */ + /* re-run all passes */ + pass = solv->updatemap.size ? 0 : 1; + continue; + } + /* reset installedpos, advance to next pass */ + installedpos = installed->start; + pass++; + } + solv->installedpos = installedpos; + return level; +} + +static int +resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + int i, j, n; + int postponed; + Rule *r; + int origlevel = level; + Id p, *dp; + + /* + * decide + */ + POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n"); + postponed = 0; + for (i = 1, n = 1; ; i++, n++) + { + if (n >= solv->nrules) + { + if (postponed <= 0) + break; + i = postponed; + postponed = -1; + n = 1; + } + if (i == solv->nrules) + i = 1; + r = solv->rules + i; + if (r->d < 0) /* ignore disabled rules */ + continue; + if (r->p < 0) /* most common cases first */ + { + if (r->d == 0 || solv->decisionmap[-r->p] <= 0) + continue; + } + if (dq->count) + queue_empty(dq); + if (r->d == 0) + { + /* binary or unary rule */ + /* need two positive undecided literals, r->p already checked above */ + if (r->w2 <= 0) + continue; + if (solv->decisionmap[r->p] || solv->decisionmap[r->w2]) + continue; + queue_push(dq, r->p); + queue_push(dq, r->w2); + } + else + { + /* make sure that + * all negative literals are installed + * no positive literal is installed + * i.e. the rule is not fulfilled and we + * just need to decide on the positive literals + * (decisionmap[-r->p] for the r->p < 0 case is already checked above) + */ + if (r->p >= 0) + { + if (solv->decisionmap[r->p] > 0) + continue; + if (solv->decisionmap[r->p] == 0) + queue_push(dq, r->p); + } + dp = pool->whatprovidesdata + r->d; + while ((p = *dp++) != 0) + { + if (p < 0) + { + if (solv->decisionmap[-p] <= 0) + break; + } + else + { + if (solv->decisionmap[p] > 0) + break; + if (solv->decisionmap[p] == 0) + queue_push(dq, p); + } + } + if (p) + continue; + } + IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) + { + POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled "); + solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r); + } + /* dq->count < 2 cannot happen as this means that + * the rule is unit */ + assert(dq->count > 1); + + /* prune to cleandeps packages */ + if (solv->cleandepsmap.size && solv->installed) + { + 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 (j < dq->count) + { + dq->elements[0] = dq->elements[j]; + queue_truncate(dq, 1); + } + } + + if (dq->count > 1 && postponed >= 0) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE_NOREORDER); + if (dq->count > 1) + { + if (!postponed) + postponed = i; + continue; + } + } + + level = selectandinstall(solv, level, dq, disablerules, r - solv->rules, SOLVER_REASON_RESOLVE); + if (level < origlevel) + break; /* trouble */ + /* something changed, so look at all rules again */ + n = 0; + } + return level; +} + + #ifdef ENABLE_COMPLEX_DEPS static void @@ -2089,6 +2372,365 @@ prune_disfavored(Solver *solv, Queue *plist) queue_truncate(plist, j); } +static int +resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, int *rerunp) +{ + Pool *pool = solv->pool; + int i, j, qcount; + int olevel; + Solvable *s; + Map dqmap; + int decisioncount; + Id p; + + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n"); + if (dq->count) + queue_empty(dq); /* recommended packages */ + if (dqs->count) + queue_empty(dqs); /* supplemented packages */ + for (i = 1; i < pool->nsolvables; i++) + { + if (solv->decisionmap[i] < 0) + continue; + s = pool->solvables + i; + if (solv->decisionmap[i] > 0) + { + /* installed, check for recommends */ + Id *recp, rec, pp, p; + if (!solv->addalreadyrecommended && s->repo == solv->installed) + continue; + /* XXX need to special case AND ? */ + if (s->recommends) + { + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, rec)) + { + add_complex_recommends(solv, rec, dq, 0); + continue; + } +#endif + qcount = dq->count; + FOR_PROVIDES(p, pp, rec) + { + if (solv->decisionmap[p] > 0) + { + dq->count = qcount; + break; + } + else if (solv->decisionmap[p] == 0) + { + if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) + continue; + queue_pushunique(dq, p); + } + } + } + } + } + else + { + /* not yet installed, check if supplemented */ + if (!s->supplements) + continue; + if (!pool_installable(pool, s)) + continue; + if (!solver_is_supplementing(solv, s)) + continue; + if (solv->dupmap_all && 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)) + continue; /* disfavored supplements, do not install */ + queue_push(dqs, i); + } + } + + /* filter out disfavored recommended packages */ + if (dq->count && solv->isdisfavormap.size) + prune_disfavored(solv, dq); + + /* filter out all packages obsoleted by installed packages */ + /* this is no longer needed if we have (and trust) reverse obsoletes */ + if ((dqs->count || dq->count) && solv->installed) + { + Map obsmap; + Id obs, *obsp, po, ppo; + + map_init(&obsmap, pool->nsolvables); + for (p = solv->installed->start; p < solv->installed->end; p++) + { + s = pool->solvables + p; + if (s->repo != solv->installed || !s->obsoletes) + continue; + if (solv->decisionmap[p] <= 0) + continue; + if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p)) + continue; + obsp = s->repo->idarraydata + s->obsoletes; + /* foreach obsoletes */ + while ((obs = *obsp++) != 0) + FOR_PROVIDES(po, ppo, obs) + { + Solvable *pos = pool->solvables + po; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos)) + continue; + MAPSET(&obsmap, po); + } + } + for (i = j = 0; i < dqs->count; i++) + if (!MAPTST(&obsmap, dqs->elements[i])) + dqs->elements[j++] = dqs->elements[i]; + dqs->count = j; + for (i = j = 0; i < dq->count; i++) + if (!MAPTST(&obsmap, dq->elements[i])) + dq->elements[j++] = dq->elements[i]; + dq->count = j; + map_free(&obsmap); + } + + /* filter out all already supplemented packages if requested */ + if (!solv->addalreadyrecommended && dqs->count) + { + /* filter out old supplements */ + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + s = pool->solvables + p; + if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s)) + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* multiversion doesn't mix well with supplements. + * filter supplemented packages where we already decided + * to install a different version (see bnc#501088) */ + if (dqs->count && solv->multiversion.size) + { + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (MAPTST(&solv->multiversion, p)) + { + Id p2, pp2; + s = pool->solvables + p; + FOR_PROVIDES(p2, pp2, s->name) + if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name) + break; + if (p2) + continue; /* ignore this package */ + } + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* implicitobsoleteusescolors doesn't mix well with supplements. + * filter supplemented packages where we already decided + * to install a different architecture */ + if (dqs->count && pool->implicitobsoleteusescolors) + { + for (i = j = 0; i < dqs->count; i++) + { + Id p2, pp2; + p = dqs->elements[i]; + s = pool->solvables + p; + FOR_PROVIDES(p2, pp2, s->name) + if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name && pool->solvables[p2].arch != s->arch) + break; + if (p2) + continue; /* ignore this package */ + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* make dq contain both recommended and supplemented pkgs */ + if (dqs->count) + { + for (i = 0; i < dqs->count; i++) + queue_pushunique(dq, dqs->elements[i]); + } + + if (!dq->count) + return level; + *rerunp = 1; + + if (dq->count == 1) + { + /* simple case, just one package. no need to choose to best version */ + p = dq->elements[0]; + if (dqs->count) + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); + else + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); + return setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + } + + /* filter packages, this gives us the best versions */ + policy_filter_unwanted(solv, dq, POLICY_MODE_RECOMMEND); + + /* create map of result */ + map_init(&dqmap, pool->nsolvables); + for (i = 0; i < dq->count; i++) + MAPSET(&dqmap, dq->elements[i]); + + /* prune dqs so that it only contains the best versions */ + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (MAPTST(&dqmap, p)) + dqs->elements[j++] = p; + } + dqs->count = j; + + /* install all supplemented packages, but order first */ + if (dqs->count > 1) + policy_filter_unwanted(solv, dqs, POLICY_MODE_SUPPLEMENT); + decisioncount = solv->decisionq.count; + for (i = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (solv->decisionmap[p]) + continue; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + if (level <= olevel) + break; + } + if (i < dqs->count || solv->decisionq.count < decisioncount) + { + map_free(&dqmap); + return level; + } + + /* install all recommended packages */ + /* more work as we want to created branches if multiple + * choices are valid */ + for (i = 0; i < decisioncount; i++) + { + Id rec, *recp, pp; + p = solv->decisionq.elements[i]; + if (p < 0) + continue; + s = pool->solvables + p; + if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed)) + continue; + if (!s->recommends) + continue; + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { + queue_empty(dq); +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, rec)) + add_complex_recommends(solv, rec, dq, &dqmap); + else +#endif + FOR_PROVIDES(p, pp, rec) + { + if (solv->decisionmap[p] > 0) + { + dq->count = 0; + break; + } + else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p)) + queue_push(dq, p); + } + if (!dq->count) + continue; + if (dq->count > 1) + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + /* if we have multiple candidates we open a branch */ + if (dq->count > 1) + createbranch(solv, level, dq, s - pool->solvables, rec); + p = dq->elements[0]; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + if (level <= olevel || solv->decisionq.count < decisioncount) + break; /* we had to revert some decisions */ + } + if (rec) + break; /* had a problem above, quit loop */ + } + map_free(&dqmap); + return level; +} + + +static int +resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *rerunp) +{ + Pool *pool = solv->pool; + int i; + Id p; + int installedone = 0; + int olevel; + + /* let's see if we can install some unsupported package */ + POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n"); + for (i = 0; i < solv->orphaned.count; i++) + { + p = solv->orphaned.elements[i]; + if (solv->decisionmap[p]) + continue; /* already decided */ + if (solv->droporphanedmap_all) + continue; + if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)) + continue; + POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + installedone = 1; + if (level < olevel) + break; + } + if (installedone || i < solv->orphaned.count) + { + *rerunp = 1; + return level; + } + for (i = 0; i < solv->orphaned.count; i++) + { + p = solv->orphaned.elements[i]; + if (solv->decisionmap[p]) + continue; /* already decided */ + POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + if (level < olevel) + { + *rerunp = 1; + return level; + } + } + if (solv->brokenorphanrules) + { + solver_check_brokenorphanrules(solv, dq); + if (dq->count) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + for (i = 0; i < dq->count; i++) + { + p = dq->elements[i]; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + if (level < olevel) + break; + } + *rerunp = 1; + } + } + return level; +} + /*------------------------------------------------------------------- * * solver_run_sat @@ -2105,12 +2747,11 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) int systemlevel; int level, olevel; Rule *r; - int i, j, n; + int i; Solvable *s; Pool *pool = solv->pool; - Id p, pp, *dp, postponed; + Id p; int minimizationsteps; - int installedpos = solv->installed ? solv->installed->start : 0; IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION) { @@ -2126,6 +2767,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) queue_init(&dq); queue_init(&dqs); + solv->installedpos = 0; + solv->do_extra_reordering = 0; /* * here's the main loop: @@ -2170,167 +2813,41 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) */ if (level < systemlevel && !solv->focus_installed) { + if (solv->installed && solv->installed->nsolvables && !solv->installed->disabled) + solv->do_extra_reordering = 1; olevel = level; level = resolve_jobrules(solv, level, disablerules, &dq); + solv->do_extra_reordering = 0; if (level < olevel) continue; systemlevel = level + 1; } + /* resolve job dependencies in the focus_best case */ + if (level < systemlevel && solv->focus_best && !solv->focus_installed && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) + { + solv->do_extra_reordering = 1; + olevel = level; + level = resolve_dependencies(solv, level, disablerules, &dq); + solv->do_extra_reordering = 0; + if (level < olevel) + continue; /* start over */ + systemlevel = level + 1; + } /* * installed packages */ - if (!solv->decisioncnt_update) - solv->decisioncnt_update = solv->decisionq.count; if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) { - Repo *installed = solv->installed; - int pass; - - POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n"); - /* we use two passes if we need to update packages - * to create a better user experience */ - for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++) - { - int passlevel = level; - Id *specialupdaters = solv->specialupdaters; - if (pass == 1 && !solv->decisioncnt_keep) - solv->decisioncnt_keep = solv->decisionq.count; - /* start with installedpos, the position that gave us problems the last time */ - for (i = installedpos, n = installed->start; n < installed->end; i++, n++) - { - Rule *rr; - Id d; - - if (i == installed->end) - i = installed->start; - s = pool->solvables + i; - if (s->repo != installed) - continue; - - if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start])) - continue; /* already decided */ - if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start)) - continue; /* updates first */ - r = solv->rules + solv->updaterules + (i - installed->start); - rr = r; - if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */ - rr -= solv->installed->end - solv->installed->start; - if (!rr->p) /* identical to update rule? */ - rr = r; - if (!rr->p) - continue; /* orpaned package or pseudo package */ - - /* check if we should update this package to the latest version - * noupdate is set for erase jobs, in that case we want to deinstall - * the installed package and not replace it with a newer version - * rr->p != i is for dup jobs where the installed package cannot be kept */ - queue_empty(&dq); - if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i))) - { - if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0) - { - /* 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); - 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) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - p = dq.elements[0]; - if (p != i && solv->decisionmap[p] == 0) - { - rr = solv->rules + solv->featurerules + (i - solv->installed->start); - if (!rr->p) /* update rule == feature rule? */ - rr = rr - solv->featurerules + solv->updaterules; - dq.count = 1; - } - else - dq.count = 0; - } - } - else - { - /* update to best package of the update rule */ - FOR_RULELITERALS(p, pp, rr) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; /* already fulfilled */ - break; - } - if (!solv->decisionmap[p]) - queue_push(&dq, p); - } - } - } - 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); - /* install best version */ - if (dq.count) - { - olevel = level; - level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules); - if (level <= olevel) - { - if (level < passlevel) - break; /* trouble */ - if (level < olevel) - n = installed->start; /* redo all */ - i--; - n--; - continue; - } - } - /* if still undecided keep package */ - if (solv->decisionmap[i] == 0) - { - olevel = level; - if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start)) - { -#if 0 - POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i)); - level = setpropagatelearn(solv, level, -i, disablerules, 0); -#else - continue; -#endif - } - else - { - POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i)); - level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules); - } - if (level <= olevel) - { - if (level < passlevel) - break; /* trouble */ - if (level < olevel) - n = installed->start; /* redo all */ - i--; - n--; - continue; /* retry with learnt rule */ - } - } - } - if (n < installed->end) - { - installedpos = i; /* retry problem solvable next time */ - break; /* ran into trouble */ - } - installedpos = installed->start; /* reset installedpos */ - } + olevel = level; + level = resolve_installed(solv, level, disablerules, &dq); + if (level < olevel) + continue; systemlevel = level + 1; - if (pass < 2) - continue; /* had trouble, retry */ } - if (!solv->decisioncnt_keep) - solv->decisioncnt_keep = solv->decisionq.count; + /* resolve jobs in focus_installed case */ if (level < systemlevel && solv->focus_installed) { olevel = level; @@ -2343,494 +2860,51 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) if (level < systemlevel) systemlevel = level; - /* - * decide - */ - if (!solv->decisioncnt_resolve) - solv->decisioncnt_resolve = solv->decisionq.count; - POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n"); - postponed = 0; - for (i = 1, n = 1; ; i++, n++) - { - if (n >= solv->nrules) - { - if (postponed <= 0) - break; - i = postponed; - postponed = -1; - n = 1; - } - if (i == solv->nrules) - i = 1; - r = solv->rules + i; - if (r->d < 0) /* ignore disabled rules */ - continue; - if (r->p < 0) /* most common cases first */ - { - if (r->d == 0 || solv->decisionmap[-r->p] <= 0) - continue; - } - if (dq.count) - queue_empty(&dq); - if (r->d == 0) - { - /* binary or unary rule */ - /* need two positive undecided literals, r->p already checked above */ - if (r->w2 <= 0) - continue; - if (solv->decisionmap[r->p] || solv->decisionmap[r->w2]) - continue; - queue_push(&dq, r->p); - queue_push(&dq, r->w2); - } - else - { - /* make sure that - * all negative literals are installed - * no positive literal is installed - * i.e. the rule is not fulfilled and we - * just need to decide on the positive literals - * (decisionmap[-r->p] for the r->p < 0 case is already checked above) - */ - if (r->p >= 0) - { - if (solv->decisionmap[r->p] > 0) - continue; - if (solv->decisionmap[r->p] == 0) - queue_push(&dq, r->p); - } - dp = pool->whatprovidesdata + r->d; - while ((p = *dp++) != 0) - { - if (p < 0) - { - if (solv->decisionmap[-p] <= 0) - break; - } - else - { - if (solv->decisionmap[p] > 0) - break; - if (solv->decisionmap[p] == 0) - queue_push(&dq, p); - } - } - if (p) - continue; - } - IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) - { - POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled "); - solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r); - } - /* dq.count < 2 cannot happen as this means that - * the rule is unit */ - assert(dq.count > 1); - - /* prune to cleandeps packages */ - if (solv->cleandepsmap.size && solv->installed) - { - 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 (j < dq.count) - { - dq.elements[0] = dq.elements[j]; - queue_truncate(&dq, 1); - } - } - - if (dq.count > 1 && postponed >= 0) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE_NOREORDER); - if (dq.count > 1) - { - if (!postponed) - postponed = i; - continue; - } - } - - olevel = level; - level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules); - if (level < systemlevel) - break; /* trouble */ - /* something changed, so look at all rules again */ - n = 0; - } - - if (n < solv->nrules) /* ran into trouble? */ + /* resolve all dependencies */ + olevel = level; + level = resolve_dependencies(solv, level, disablerules, &dq); + if (level < olevel) continue; /* start over */ /* decide leftover cleandeps packages */ if (solv->cleandepsmap.size && solv->installed) - { - for (p = solv->installed->start; p < solv->installed->end; p++) - { - s = pool->solvables + p; - if (s->repo != solv->installed) - continue; - if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start)) - { - POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, -p, 0, 0); - if (level < olevel) - break; - } - } - if (p < solv->installed->end) - continue; - } + { + for (p = solv->installed->start; p < solv->installed->end; p++) + { + s = pool->solvables + p; + if (s->repo != solv->installed) + continue; + if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start)) + { + POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE); + if (level < olevel) + break; + } + } + if (p < solv->installed->end) + continue; + } /* at this point we have a consistent system. now do the extras... */ - if (!solv->decisioncnt_weak) - solv->decisioncnt_weak = solv->decisionq.count; if (doweak) { - int qcount; - - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n"); - queue_empty(&dq); /* recommended packages */ - queue_empty(&dqs); /* supplemented packages */ - for (i = 1; i < pool->nsolvables; i++) - { - if (solv->decisionmap[i] < 0) - continue; - if (solv->decisionmap[i] > 0) - { - /* installed, check for recommends */ - Id *recp, rec, pp, p; - s = pool->solvables + i; - if (!solv->addalreadyrecommended && s->repo == solv->installed) - continue; - /* XXX need to special case AND ? */ - if (s->recommends) - { - recp = s->repo->idarraydata + s->recommends; - while ((rec = *recp++) != 0) - { -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, rec)) - { - add_complex_recommends(solv, rec, &dq, 0); - continue; - } -#endif - qcount = dq.count; - FOR_PROVIDES(p, pp, rec) - { - if (solv->decisionmap[p] > 0) - { - dq.count = qcount; - break; - } - else if (solv->decisionmap[p] == 0) - { - if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) - continue; - queue_pushunique(&dq, p); - } - } - } - } - } - else - { - s = pool->solvables + i; - if (!s->supplements) - continue; - if (!pool_installable(pool, s)) - continue; - if (!solver_is_supplementing(solv, s)) - continue; - if (solv->dupmap_all && 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)) - continue; /* disfavored supplements, do not install */ - queue_push(&dqs, i); - } - } - - /* filter out disfavored recommended packages */ - if (dq.count && solv->isdisfavormap.size) - prune_disfavored(solv, &dq); - - /* filter out all packages obsoleted by installed packages */ - /* this is no longer needed if we have reverse obsoletes */ - if ((dqs.count || dq.count) && solv->installed) - { - Map obsmap; - Id obs, *obsp, po, ppo; - - map_init(&obsmap, pool->nsolvables); - for (p = solv->installed->start; p < solv->installed->end; p++) - { - s = pool->solvables + p; - if (s->repo != solv->installed || !s->obsoletes) - continue; - if (solv->decisionmap[p] <= 0) - continue; - if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p)) - continue; - obsp = s->repo->idarraydata + s->obsoletes; - /* foreach obsoletes */ - while ((obs = *obsp++) != 0) - FOR_PROVIDES(po, ppo, obs) - { - Solvable *pos = pool->solvables + po; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos)) - continue; - MAPSET(&obsmap, po); - } - } - for (i = j = 0; i < dqs.count; i++) - if (!MAPTST(&obsmap, dqs.elements[i])) - dqs.elements[j++] = dqs.elements[i]; - dqs.count = j; - for (i = j = 0; i < dq.count; i++) - if (!MAPTST(&obsmap, dq.elements[i])) - dq.elements[j++] = dq.elements[i]; - dq.count = j; - map_free(&obsmap); - } - - /* filter out all already supplemented packages if requested */ - if (!solv->addalreadyrecommended && dqs.count) - { - /* filter out old supplements */ - for (i = j = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - s = pool->solvables + p; - if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s)) - dqs.elements[j++] = p; - } - dqs.count = j; - } - - /* multiversion doesn't mix well with supplements. - * filter supplemented packages where we already decided - * to install a different version (see bnc#501088) */ - if (dqs.count && solv->multiversion.size) - { - for (i = j = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - if (MAPTST(&solv->multiversion, p)) - { - Id p2, pp2; - s = pool->solvables + p; - FOR_PROVIDES(p2, pp2, s->name) - if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name) - break; - if (p2) - continue; /* ignore this package */ - } - dqs.elements[j++] = p; - } - dqs.count = j; - } - - /* implicitobsoleteusescolors doesn't mix well with supplements. - * filter supplemented packages where we already decided - * to install a different architecture */ - if (dqs.count && pool->implicitobsoleteusescolors) - { - for (i = j = 0; i < dqs.count; i++) - { - Id p2, pp2; - p = dqs.elements[i]; - s = pool->solvables + p; - FOR_PROVIDES(p2, pp2, s->name) - if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name && pool->solvables[p2].arch != s->arch) - break; - if (p2) - continue; /* ignore this package */ - dqs.elements[j++] = p; - } - dqs.count = j; - } - - /* make dq contain both recommended and supplemented pkgs */ - if (dqs.count) - { - for (i = 0; i < dqs.count; i++) - queue_pushunique(&dq, dqs.elements[i]); - } - - if (dq.count) - { - Map dqmap; - int decisioncount = solv->decisionq.count; - - if (dq.count == 1) - { - /* simple case, just one package. no need to choose to best version */ - p = dq.elements[0]; - if (dqs.count) - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); - else - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); - level = setpropagatelearn(solv, level, p, 0, 0); - continue; /* back to main loop */ - } - - /* filter packages, this gives us the best versions */ - policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND); - - /* create map of result */ - map_init(&dqmap, pool->nsolvables); - for (i = 0; i < dq.count; i++) - MAPSET(&dqmap, dq.elements[i]); - - /* prune dqs so that it only contains the best versions */ - for (i = j = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - if (MAPTST(&dqmap, p)) - dqs.elements[j++] = p; - } - dqs.count = j; - - /* install all supplemented packages, but order first */ - if (dqs.count > 1) - policy_filter_unwanted(solv, &dqs, POLICY_MODE_SUPPLEMENT); - for (i = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - if (solv->decisionmap[p]) - continue; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level <= olevel) - break; - } - if (i < dqs.count || solv->decisionq.count < decisioncount) - { - map_free(&dqmap); - continue; - } - - /* install all recommended packages */ - /* more work as we want to created branches if multiple - * choices are valid */ - for (i = 0; i < decisioncount; i++) - { - Id rec, *recp, pp; - p = solv->decisionq.elements[i]; - if (p < 0) - continue; - s = pool->solvables + p; - if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed)) - continue; - if (!s->recommends) - continue; - recp = s->repo->idarraydata + s->recommends; - while ((rec = *recp++) != 0) - { - queue_empty(&dq); -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, rec)) - add_complex_recommends(solv, rec, &dq, &dqmap); - else -#endif - FOR_PROVIDES(p, pp, rec) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; - break; - } - else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p)) - queue_push(&dq, p); - } - if (!dq.count) - continue; - if (dq.count > 1) - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - /* if we have multiple candidates we open a branch */ - if (dq.count > 1) - createbranch(solv, level, &dq, s - pool->solvables, rec); - p = dq.elements[0]; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level <= olevel || solv->decisionq.count < decisioncount) - break; /* we had to revert some decisions */ - } - if (rec) - break; /* had a problem above, quit loop */ - } - map_free(&dqmap); - continue; /* back to main loop so that all deps are checked */ - } + int rerun = 0; + level = resolve_weak(solv, level, disablerules, &dq, &dqs, &rerun); + if (rerun) + continue; } - if (!solv->decisioncnt_orphan) - solv->decisioncnt_orphan = solv->decisionq.count; if (solv->installed && (solv->orphaned.count || solv->brokenorphanrules)) { - int installedone = 0; - - /* let's see if we can install some unsupported package */ - POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n"); - for (i = 0; i < solv->orphaned.count; i++) - { - p = solv->orphaned.elements[i]; - if (solv->decisionmap[p]) - continue; /* already decided */ - if (solv->droporphanedmap_all) - continue; - if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)) - continue; - POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - installedone = 1; - if (level < olevel) - break; - } - if (installedone || i < solv->orphaned.count) - continue; /* back to main loop */ - for (i = 0; i < solv->orphaned.count; i++) - { - p = solv->orphaned.elements[i]; - if (solv->decisionmap[p]) - continue; /* already decided */ - POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, -p, 0, 0); - if (level < olevel) - break; - } - if (i < solv->orphaned.count) - continue; /* back to main loop */ - if (solv->brokenorphanrules) - { - solver_check_brokenorphanrules(solv, &dq); - if (dq.count) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - for (i = 0; i < dq.count; i++) - { - p = dq.elements[i]; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level < olevel) - break; - } - continue; - } - } + int rerun = 0; + level = resolve_orphaned(solv, level, disablerules, &dq, &rerun); + if (rerun) + continue; } - + /* one final pass to make sure we decided all installed packages */ if (solv->installed) { @@ -2843,7 +2917,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) continue; POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing unwanted %s\n", pool_solvid2str(pool, p)); olevel = level; - level = setpropagatelearn(solv, level, -p, 0, 0); + level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE); if (level < olevel) break; } @@ -2950,22 +3024,13 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) /* no minimization found, we're finally finished! */ break; } + assert(level == -1 || level + 1 == solv->decisionq_reason.count); POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps); POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n"); queue_free(&dq); queue_free(&dqs); - if (level < 0) - { - /* unsolvable */ - solv->decisioncnt_jobs = solv->decisionq.count; - solv->decisioncnt_update = solv->decisionq.count; - solv->decisioncnt_keep = solv->decisionq.count; - solv->decisioncnt_resolve = solv->decisionq.count; - solv->decisioncnt_weak = solv->decisionq.count; - solv->decisioncnt_orphan = solv->decisionq.count; - } #if 0 solver_printdecisionq(solv, SOLV_DEBUG_RESULT); #endif @@ -3141,8 +3206,10 @@ solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap) Solvable *s; Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - MAPSET(multiversionmap, p); + { + FOR_REPO_SOLVABLES(repo, p, s) + MAPSET(multiversionmap, p); + } } FOR_JOB_SELECT(p, pp, select, what) MAPSET(multiversionmap, p); @@ -3513,7 +3580,7 @@ solver_solve(Solver *solv, Queue *job) memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id)); queue_empty(&solv->decisionq); queue_empty(&solv->decisionq_why); - solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; + queue_empty(&solv->decisionq_reason); queue_empty(&solv->learnt_why); queue_empty(&solv->learnt_pool); queue_empty(&solv->branches); @@ -3947,8 +4014,10 @@ solver_solve(Solver *solv, Queue *job) { Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, -p, 0, 0, i, weak); + { + FOR_REPO_SOLVABLES(repo, p, s) + solver_addjobrule(solv, -p, 0, 0, i, weak); + } } #ifdef ENABLE_COMPLEX_DEPS else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what)) @@ -4023,8 +4092,10 @@ solver_solve(Solver *solv, Queue *job) { Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); + { + FOR_REPO_SOLVABLES(repo, p, s) + solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); + } } FOR_JOB_SELECT(p, pp, select, what) solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); @@ -4284,20 +4355,12 @@ void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *su MAPZERO(&solv->recommendsmap); /* put all packages the solver already chose in the map */ - if (solv->decisioncnt_weak) - { - for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++) - { - Id why; - why = solv->decisionq_why.elements[i]; - if (why) - continue; /* forced by unit rule or dep resolving */ - p = solv->decisionq.elements[i]; - if (p < 0) - continue; + for (i = 1; i < solv->decisionq.count; i++) + if ((p = solv->decisionq.elements[i]) > 0 && solv->decisionq_why.elements[i] == 0) + { + if (solv->decisionq_reason.elements[solv->decisionmap[p]] == SOLVER_REASON_WEAKDEP) MAPSET(&solv->recommendsmap, p); - } - } + } for (i = 0; i < solv->decisionq.count; i++) { @@ -4565,36 +4628,8 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) *infop = why > 0 ? why : -why; if (why > 0) return SOLVER_REASON_UNIT_RULE; - why = -why; - if (i == 0) - return SOLVER_REASON_KEEP_INSTALLED; /* the systemsolvable */ - if (i < solv->decisioncnt_update) - return SOLVER_REASON_RESOLVE_JOB; - if (i < solv->decisioncnt_keep) - { - if (why == 0 && pp < 0) - return SOLVER_REASON_CLEANDEPS_ERASE; - return SOLVER_REASON_UPDATE_INSTALLED; - } - if (i < solv->decisioncnt_resolve) - { - if (solv->focus_installed && i >= solv->decisioncnt_jobs) - return SOLVER_REASON_RESOLVE_JOB; - if (why == 0 && pp < 0) - return SOLVER_REASON_CLEANDEPS_ERASE; - return SOLVER_REASON_KEEP_INSTALLED; - } - if (i < solv->decisioncnt_weak) - { - if (why == 0 && pp < 0) - return SOLVER_REASON_CLEANDEPS_ERASE; - } - if (why > 0) - return SOLVER_REASON_RESOLVE; - /* weak or orphaned */ - if (i < solv->decisioncnt_orphan) - return SOLVER_REASON_WEAKDEP; - return SOLVER_REASON_RESOLVE_ORPHAN; + i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p]; + return solv->decisionq_reason.elements[i]; } @@ -4615,7 +4650,8 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq) break; if (decisionno == solv->decisionq.count) return; /* huh? */ - if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan) + i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p]; + if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP) return; /* huh? */ /* 1) list all packages that recommend us */ @@ -4716,8 +4752,10 @@ pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what) Repo *repo = pool_id2repo(pool, what); Solvable *s; if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - queue_push(pkgs, p); + { + FOR_REPO_SOLVABLES(repo, p, s) + queue_push(pkgs, p); + } } else { @@ -4873,8 +4911,10 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags) what = solv->job.elements[i + 1]; select = how & SOLVER_SELECTMASK; if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) - FOR_REPO_SOLVABLES(installed, p, s) - MAPSET(&userinstalled, p - installed->start); + { + FOR_REPO_SOLVABLES(installed, p, s) + MAPSET(&userinstalled, p - installed->start); + } FOR_JOB_SELECT(p, pp, select, what) if (pool->solvables[p].repo == installed) MAPSET(&userinstalled, p - installed->start); diff --git a/src/solver.h b/src/solver.h index 758f1eb..be240c9 100644 --- a/src/solver.h +++ b/src/solver.h @@ -107,19 +107,13 @@ struct _Solver { /* our decisions: */ Queue decisionq; /* >0:install, <0:remove/conflict */ Queue decisionq_why; /* index of rule, Offset into rules */ + Queue decisionq_reason; /* reason for decision, indexed by level */ Id *decisionmap; /* map for all available solvables, * = 0: undecided * > 0: level of decision when installed, * < 0: level of decision when conflict */ - int decisioncnt_jobs; - int decisioncnt_update; - int decisioncnt_keep; - int decisioncnt_resolve; - int decisioncnt_weak; - int decisioncnt_orphan; - /* learnt rule history */ Queue learnt_why; Queue learnt_pool; @@ -166,6 +160,7 @@ struct _Solver { int bestobeypolicy; /* true: stay in policy with the best rules */ int noautotarget; /* true: do not assume targeted for up/dup jobs that contain no installed solvable */ int focus_installed; /* true: resolve update rules first */ + int focus_best; /* true: resolve job dependencies first */ int do_yum_obsoletes; /* true: add special yumobs rules */ int urpmreorder; /* true: do special urpm package reordering */ @@ -203,6 +198,9 @@ struct _Solver { Queue *favorq; Map favormap; /* favored / disfavored packages */ Map isdisfavormap; + + int installedpos; /* for resolve_installed */ + int do_extra_reordering; /* reorder for future installed packages */ #endif /* LIBSOLV_INTERNAL */ }; @@ -309,6 +307,7 @@ typedef struct _Solver Solver; #define SOLVER_FLAG_YUM_OBSOLETES 21 #define SOLVER_FLAG_NEED_UPDATEPROVIDE 22 #define SOLVER_FLAG_URPM_REORDER 23 +#define SOLVER_FLAG_FOCUS_BEST 24 #define GET_USERINSTALLED_NAMES (1 << 0) /* package names instead of ids */ #define GET_USERINSTALLED_INVERTED (1 << 1) /* autoinstalled */ diff --git a/src/solvversion.h.in b/src/solvversion.h.in index 75dc63f..9f59d75 100644 --- a/src/solvversion.h.in +++ b/src/solvversion.h.in @@ -28,6 +28,7 @@ extern int solv_version_patch; #cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS #cmakedefine LIBSOLV_FEATURE_MULTI_SEMANTICS +#cmakedefine LIBSOLVEXT_FEATURE_RPMPKG #cmakedefine LIBSOLVEXT_FEATURE_RPMDB #cmakedefine LIBSOLVEXT_FEATURE_RPMDB_BYRPMHEADER #cmakedefine LIBSOLVEXT_FEATURE_PUBKEY |