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