- add decision introspection (untested)
authorMichael Schroeder <mls@suse.de>
Mon, 6 Jun 2011 12:14:02 +0000 (14:14 +0200)
committerMichael Schroeder <mls@suse.de>
Mon, 6 Jun 2011 12:14:15 +0000 (14:14 +0200)
src/libsolv.ver
src/solver.c
src/solver.h
src/solver_private.h

index d027fa2..f674226 100644 (file)
@@ -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;
index 4e15466..7a2c2f8 100644 (file)
@@ -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];
+       }
+    }
+}
index 64d47be..9614202 100644 (file)
@@ -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);
 
index 47f3f9e..cc37e11 100644 (file)
@@ -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;