From 6783d8e6f45c17f5401210d4441bea461a145eaf Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Mon, 6 Jun 2011 14:14:02 +0200 Subject: [PATCH] - add decision introspection (untested) --- src/libsolv.ver | 6 ++ src/solver.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/solver.h | 24 ++++++ src/solver_private.h | 3 + 4 files changed, 272 insertions(+), 1 deletion(-) diff --git a/src/libsolv.ver b/src/libsolv.ver index d027fa2..f674226 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -243,12 +243,18 @@ SOLV_1.0 { solver_create; solver_create_decisions_obsoletesmap; solver_create_state_maps; + solver_describe_decision; + solver_describe_weakdep_decision; solver_disableproblem; solver_enableproblem; solver_findallproblemrules; solver_findproblemrule; solver_free; solver_freedupmaps; + solver_get_decisionblock; + solver_get_decisionlevel; + solver_get_decisionqueue; + solver_get_lastdecisionblocklevel; solver_next_problem; solver_next_solution; solver_next_solutionelement; diff --git a/src/solver.c b/src/solver.c index 4e15466..7a2c2f8 100644 --- a/src/solver.c +++ b/src/solver.c @@ -1473,9 +1473,10 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) systemlevel = level + 1; if (i < solv->jobrules_end) continue; + solv->decisioncnt_update = solv->decisionq.count; + solv->decisioncnt_keep = solv->decisionq.count; } - /* * installed packages */ @@ -1490,6 +1491,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++) { int passlevel = level; + if (pass == 1) + solv->decisioncnt_keep = solv->decisionq.count; /* start with installedpos, the position that gave us problems last time */ for (i = installedpos, n = installed->start; n < installed->end; i++, n++) { @@ -1627,6 +1630,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) /* * decide */ + solv->decisioncnt_resolve = solv->decisionq.count; POOL_DEBUG(SAT_DEBUG_POLICY, "deciding unresolved rules\n"); for (i = 1, n = 1; n < solv->nrules; i++, n++) { @@ -2110,6 +2114,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) if (level == 0) { /* unsolvable */ + 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; } @@ -3068,3 +3075,234 @@ solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res) map_free(&installedmap); } +int +solver_get_decisionlevel(Solver *solv, Id p) +{ + return solv->decisionmap[p]; +} + +void +solver_get_decisionqueue(Solver *solv, Queue *decisionq) +{ + queue_free(decisionq); + queue_init_clone(decisionq, &solv->decisionq); +} + +int +solver_get_lastdecisionblocklevel(Solver *solv) +{ + Id p; + if (solv->decisionq.count == 0) + return 0; + p = solv->decisionq.elements[solv->decisionq.count - 1]; + if (p < 0) + p = -p; + return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p]; +} + +void +solver_get_decisionblock(Solver *solv, int level, Queue *decisionq) +{ + Id p; + int i; + + queue_empty(decisionq); + for (i = 0; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p < 0) + p = -p; + if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level) + break; + } + if (i == solv->decisionq.count) + return; + for (i = 0; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p < 0) + p = -p; + if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level) + queue_push(decisionq, p); + else + break; + } +} + +int +solver_describe_decision(Solver *solv, Id p, Id *infop) +{ + int i; + Id pp, why; + + if (infop) + *infop = 0; + if (!solv->decisionmap[p]) + return SOLVER_REASON_UNRELATED; + pp = solv->decisionmap[p] < 0 ? -p : p; + for (i = 0; i < solv->decisionq.count; i++) + if (solv->decisionq.elements[i] == pp) + break; + if (i == solv->decisionq.count) /* just in case... */ + return SOLVER_REASON_UNRELATED; + why = solv->decisionq_why.elements[i]; + if (why > 0) + { + if (infop) + *infop = why; + return SOLVER_REASON_UNIT_RULE; + } + why = -why; + if (i < solv->decisioncnt_update) + { + if (i == 0) + { + if (infop) + *infop = SYSTEMSOLVABLE; + return SOLVER_REASON_KEEP_INSTALLED; + } + if (infop) + *infop = why; + return SOLVER_REASON_RESOLVE_JOB; + } + if (i < solv->decisioncnt_keep) + { + if (why == 0 && pp < 0) + return SOLVER_REASON_CLEANDEPS_ERASE; + if (infop) + { + if (why >= solv->updaterules && why < solv->updaterules_end) + *infop = why - solv->updaterules; + else if (why >= solv->featurerules && why < solv->featurerules_end) + *infop = why - solv->featurerules; + } + return SOLVER_REASON_UPDATE_INSTALLED; + } + if (i < solv->decisioncnt_resolve) + { + if (why == 0 && pp < 0) + return SOLVER_REASON_CLEANDEPS_ERASE; + if (infop) + { + if (why >= solv->updaterules && why < solv->updaterules_end) + *infop = why - solv->updaterules; + else if (why >= solv->featurerules && why < solv->featurerules_end) + *infop = why - solv->featurerules; + } + return SOLVER_REASON_KEEP_INSTALLED; + } + if (i < solv->decisioncnt_weak) + { + if (infop) + *infop = why; + return SOLVER_REASON_RESOLVE; + } + if (solv->decisionq.count < solv->decisioncnt_orphan) + return SOLVER_REASON_WEAKDEP; + return SOLVER_REASON_RESOLVE_ORPHAN; +} + + +void +solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq) +{ + Pool *pool = solv->pool; + int i; + int level = solv->decisionmap[p]; + int decisionno; + Solvable *s; + + queue_empty(whyq); + if (level < 0) + return; /* huh? */ + for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++) + if (solv->decisionq.elements[decisionno] == p) + break; + if (decisionno == solv->decisionq.count) + return; /* huh? */ + if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan) + return; /* huh? */ + + /* 1) list all packages that recommend us */ + for (i = 1; i < pool->nsolvables; i++) + { + Id *recp, rec, pp2, p2; + if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level) + continue; + s = pool->solvables + i; + if (!s->recommends) + continue; + if (solv->ignorealreadyrecommended && s->repo == solv->installed) + continue; + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { + int found = 0; + FOR_PROVIDES(p2, pp2, rec) + { + if (p2 == p) + found = 1; + else + { + /* if p2 is already installed, this recommends is ignored */ + if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level) + break; + } + } + if (!p2 && found) + { + queue_push(whyq, SOLVER_REASON_RECOMMENDED); + queue_push2(whyq, p2, rec); + } + } + } + /* 2) list all supplements */ + s = pool->solvables + p; + if (s->supplements && level > 0) + { + Id *supp, sup, pp2, p2; + int suppstart; + /* this is a hack. to use solver_dep_fulfilled we temporarily clear + * everything above our level in the decisionmap */ + for (i = decisionno; i < solv->decisionq.count; i++ ) + { + p2 = solv->decisionq.elements[i]; + if (p2 > 0) + solv->decisionmap[p2] = -solv->decisionmap[p2]; + } + supp = s->repo->idarraydata + s->supplements; + suppstart = whyq->count; + while ((sup = *supp++) != 0) + if (solver_dep_fulfilled(solv, sup)) + { + int found = 0; + /* let's see if this is an easy supp */ + FOR_PROVIDES(p2, pp2, sup) + { + if (solv->ignorealreadyrecommended && solv->installed) + { + if (pool->solvables[p2].repo == solv->installed) + continue; + } + if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level) + { + queue_push(whyq, SOLVER_REASON_SUPPLEMENTED); + queue_push2(whyq, p2, sup); + found = 1; + } + } + if (!found) + { + /* hard case, just note with no package */ + queue_push(whyq, SOLVER_REASON_SUPPLEMENTED); + queue_push2(whyq, 0, sup); + } + } + for (i = decisionno; i < solv->decisionq.count; i++) + { + p2 = solv->decisionq.elements[i]; + if (p2 > 0) + solv->decisionmap[p2] = -solv->decisionmap[p2]; + } + } +} diff --git a/src/solver.h b/src/solver.h index 64d47be..9614202 100644 --- a/src/solver.h +++ b/src/solver.h @@ -109,6 +109,9 @@ struct _Solver { * > 0: level of decision when installed, * < 0: level of decision when conflict */ + int decisioncnt_update; + int decisioncnt_keep; + int decisioncnt_resolve; int decisioncnt_weak; int decisioncnt_orphan; @@ -257,10 +260,31 @@ typedef struct _Solver Solver; #define SOLVER_SETMASK 0x2f000000 +#define SOLVER_REASON_UNRELATED 0 +#define SOLVER_REASON_UNIT_RULE 1 +#define SOLVER_REASON_KEEP_INSTALLED 2 +#define SOLVER_REASON_RESOLVE_JOB 3 +#define SOLVER_REASON_UPDATE_INSTALLED 4 +#define SOLVER_REASON_CLEANDEPS_ERASE 5 +#define SOLVER_REASON_RESOLVE 6 +#define SOLVER_REASON_WEAKDEP 7 +#define SOLVER_REASON_RESOLVE_ORPHAN 8 + +#define SOLVER_REASON_RECOMMENDED 16 +#define SOLVER_REASON_SUPPLEMENTED 17 + extern Solver *solver_create(Pool *pool); extern void solver_free(Solver *solv); extern int solver_solve(Solver *solv, Queue *job); +extern int solver_get_decisionlevel(Solver *solv, Id p); +extern void solver_get_decisionqueue(Solver *solv, Queue *decisionq); +extern int solver_get_lastdecisionblocklevel(Solver *solv); +extern void solver_get_decisionblock(Solver *solv, int level, Queue *decisionq); +extern int solver_describe_decision(Solver *solv, Id p, Id *infop); +extern void solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq); + + extern void solver_calculate_noobsmap(Pool *pool, Queue *job, Map *noobsmap); extern void solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap); diff --git a/src/solver_private.h b/src/solver_private.h index 47f3f9e..cc37e11 100644 --- a/src/solver_private.h +++ b/src/solver_private.h @@ -86,6 +86,9 @@ struct _Solver { * > 0: level of decision when installed, * < 0: level of decision when conflict */ + int decisioncnt_update; + int decisioncnt_keep; + int decisioncnt_resolve; int decisioncnt_weak; int decisioncnt_orphan; -- 2.7.4