From 3ef3b1fc2683e955702472e838ff02bf2f68954a Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Thu, 17 Apr 2014 14:18:42 +0200 Subject: [PATCH] implement SOLVER_FLAG_BREAK_ORPHANS --- src/problems.c | 4 +++ src/rules.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/rules.h | 3 ++ src/solver.c | 26 ++++++++++++++++ src/solver.h | 1 + 5 files changed, 127 insertions(+), 1 deletion(-) diff --git a/src/problems.c b/src/problems.c index 7258c04..bb00aa6 100644 --- a/src/problems.c +++ b/src/problems.c @@ -160,6 +160,10 @@ enableweakrules(Solver *solv) continue; solver_enablerule(solv, r); } + /* make sure broken orphan rules stay disabled */ + if (solv->brokenorphanrules) + for (i = 0; i < solv->brokenorphanrules->count; i++) + solver_disablerule(solv, solv->rules + solv->brokenorphanrules->elements[i]); } diff --git a/src/rules.c b/src/rules.c index b86ad77..78cc1e0 100644 --- a/src/rules.c +++ b/src/rules.c @@ -4329,4 +4329,96 @@ solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered) map_free(&cleandepsmap); } -/* EOF */ + +void +solver_breakorphans(Solver *solv) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + int i, rid; + Map m; + + if (!installed || solv->droporphanedmap_all) + return; + solv->brokenorphanrules = solv_calloc(1, sizeof(Queue)); + queue_init(solv->brokenorphanrules); + map_init(&m, installed->end - installed->start); + for (i = 0; i < solv->orphaned.count; i++) + { + Id p = solv->orphaned.elements[i]; + if (pool->solvables[p].repo != installed) + continue; + if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - installed->start)) + continue; + MAPSET(&m, p - installed->start); + } + for (rid = 1; rid < solv->rpmrules_end ; rid++) + { + Id p, *dp; + Rule *r = solv->rules + rid; + /* ignore non-deps and simple conflicts */ + if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0)) + continue; + p = -r->p; + if (p < installed->start || p >= installed->end || !MAPTST(&m, p - installed->start)) + { + /* need to check other literals */ + if (r->d == 0 || r->d == -1) + continue; + for (dp = pool->whatprovidesdata + (r->d < 0 ? -r->d - 1 : r->d); *dp < 0; dp++) + { + p = -*dp; + if (p >= installed->start && p < installed->end && MAPTST(&m, p - installed->start)) + break; + } + if (*dp >= 0) + continue; + } + /* ok, disable this rule */ + queue_push(solv->brokenorphanrules, rid); + if (r->d >= 0) + solver_disablerule(solv, r); + } + map_free(&m); + if (!solv->brokenorphanrules->count) + { + queue_free(solv->brokenorphanrules); + solv->brokenorphanrules = solv_free(solv->brokenorphanrules); + } +} + +void +solver_check_brokenorphanrules(Solver *solv, Queue *dq) +{ + Pool *pool = solv->pool; + int i; + Id l, pp; + + queue_empty(dq); + if (!solv->brokenorphanrules) + return; + for (i = 0; i < solv->brokenorphanrules->count; i++) + { + int rid = solv->brokenorphanrules->elements[i]; + Rule *r = solv->rules + rid; + FOR_RULELITERALS(l, pp, r) + { + if (l < 0) + { + if (solv->decisionmap[-l] <= 0) + break; + } + else + { + if (solv->decisionmap[l] > 0 && pool->solvables[l].repo != solv->installed) + break; + } + } + if (l) + continue; + FOR_RULELITERALS(l, pp, r) + if (l > 0 && solv->decisionmap[l] == 0 && pool->solvables[l].repo != solv->installed) + queue_pushunique(dq, l); + } +} + diff --git a/src/rules.h b/src/rules.h index 15de00f..06048e4 100644 --- a/src/rules.h +++ b/src/rules.h @@ -142,6 +142,9 @@ extern Id solver_rule2job(struct _Solver *solv, Id rid, Id *whatp); extern Id solver_rule2solvable(struct _Solver *solv, Id rid); extern void solver_rule2rules(struct _Solver *solv, Id rid, Queue *q, int recursive); +/* orphan handling */ +extern void solver_breakorphans(struct _Solver *solv); +extern void solver_check_brokenorphanrules(struct _Solver *solv, Queue *dq); #ifdef __cplusplus } diff --git a/src/solver.c b/src/solver.c index 054567e..282dd78 100644 --- a/src/solver.c +++ b/src/solver.c @@ -1573,6 +1573,7 @@ solver_free(Solver *solv) queuep_free(&solv->installsuppdepq); queuep_free(&solv->recommendscplxq); queuep_free(&solv->suggestscplxq); + queuep_free(&solv->brokenorphanrules); map_free(&solv->recommendsmap); map_free(&solv->suggestsmap); @@ -2687,6 +2688,26 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) break; 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; + } + if (level == 0) + break; + continue; + } + } } /* one final pass to make sure we decided all installed packages */ @@ -3303,6 +3324,7 @@ solver_solve(Solver *solv, Queue *job) queuep_free(&solv->suggestscplxq); solv->recommends_index = 0; } + queuep_free(&solv->brokenorphanrules); solv->specialupdaters = solv_free(solv->specialupdaters); @@ -3880,6 +3902,10 @@ solver_solve(Solver *solv, Queue *job) /* disable update rules that conflict with our job */ solver_disablepolicyrules(solv); + /* break orphans if requested */ + if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans) + solver_breakorphans(solv); + /* make initial decisions based on assertion rules */ makeruledecisions(solv); POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count); diff --git a/src/solver.h b/src/solver.h index 3316e76..c8f51fc 100644 --- a/src/solver.h +++ b/src/solver.h @@ -187,6 +187,7 @@ struct _Solver { Id *instbuddy; /* buddies of installed packages */ int keep_orphans; /* how to treat orphans */ int break_orphans; /* how to treat orphans */ + Queue *brokenorphanrules; /* broken rules of orphaned packages */ #endif /* LIBSOLV_INTERNAL */ }; -- 2.7.4