[Aptitude-svn-commit] r3794 - in branches/aptitude-0.3/aptitude: . src/generic/problemresolver

Daniel Burrows dburrows at costa.debian.org
Tue Aug 9 23:21:41 UTC 2005


Author: dburrows
Date: Tue Aug  9 23:21:38 2005
New Revision: 3794

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
Log:
Add framework for forbidding individual versions.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Tue Aug  9 23:21:38 2005
@@ -1,5 +1,9 @@
 2005-08-09  Daniel Burrows  <dburrows at debian.org>
 
+	* src/generic/problemresolver/problemresolver.h:
+
+	  Add initial support for user-forbidden versions.
+
 	* src/solution_screen.cc:
 
 	  Fix item highlighting.

Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h	Tue Aug  9 23:21:38 2005
@@ -504,6 +504,13 @@
  *  dependency is satisfied by one and not the other, it appears in
  *  the revdeps list of at least one of the versions.  (this allows
  *  apt's conflicts to be handled efficiently)
+ *
+ *  The client can request that particular package versions not appear
+ *  in generated solutions, or cancel such requests, by using the
+ *  "forbid_version" and "unforbid_version" methods.  Solutions that
+ *  are held up by a "forbid_version" invocation will be returned to
+ *  the search queue when a corresponding "unforbid_version" is
+ *  issued.
  */
 
 
@@ -602,6 +609,11 @@
   /** If \b true, we have exhausted the list of solutions. */
   bool finished:1;
 
+  /** If \b true, it is possible that some deferred solutions are
+   *  no longer forbidden.
+   */
+  bool forbiddings_dirty:1;
+
   bool debug:1;
 
   /** The working queue: */
@@ -610,9 +622,80 @@
   /** Stores already-seen solutions: */
   std::set<solution, solution_contents_compare> closed;
 
+  /** Stores solutions that were ignored because of user constraints
+   *  (but could be reinstated later).  Disjoint with closed.
+   */
+  std::set<solution, solution_contents_compare> deferred;
+
+  /** Stores versions that have been forbidden by the user; distinct
+   *  from the per-solution forbid sets that track changes on a single
+   *  inference path.
+   */
+  std::set<version> user_forbidden;
+
   /** Stores generated solutions: */
   std::vector<solution> generated_solutions;
 
+  /** Calculate whether the solution is forbidden based on
+   *  user_forbidden by testing whether the intersection of the
+   *  solution and the forbidden set is nonempty.
+   */
+  bool is_forbidden(const solution &s)
+  {
+    typename std::set<version>::const_iterator uf_iter
+      = user_forbidden.begin();
+
+    typename std::map<package, action>::const_iterator s_iter
+      = s.get_actions().begin();
+
+    while(uf_iter != user_forbidden.end() &&
+	  s_iter  != s.get_actions().end())
+      {
+	if(*uf_iter == s_iter->second.ver)
+	  return true;
+	else if(*uf_iter < s_iter->second.ver)
+	  ++uf_iter;
+	else
+	  ++s_iter;
+      }
+
+    return false;
+  }
+
+  /** Place any solutions that were deferred and are no longer
+   *  forbidden back on the open queue.
+   */
+  void reexamine_deferred()
+  {
+    // NB: the STL guarantees that erasing elements from a set does
+    // not invalidate existing iterators.  Hence this very careful
+    // iteration:
+
+    typename std::set<solution, solution_contents_compare>::const_iterator
+      i = deferred.begin(), j = i;
+
+    while(i != deferred.end())
+      {
+	++j;
+
+	if(!is_forbidden(*i))
+	  {
+	    open.push(*i);
+	    deferred.erase(i);
+	  }
+
+	i = j;
+      }
+
+    // Note that we might have to rescind the "finished" state: the
+    // actions above can actually cause new solutions to be available
+    // for processing!
+    if(finished && !open.empty())
+      finished = false;
+
+    forbiddings_dirty = false;
+  }
+
   /** Represents a possible successor to the given solution, created
    *  by installing a single 'new' version.
    */
@@ -796,29 +879,41 @@
   {
     solution s2=do_install(s, abegin, aend, forbidden_iter);
 
-    if(!irrelevant(s2))
+    if(irrelevant(s2))
       {
 	if(debug)
 	  {
-	    std::cout << "Enqueuing ";
+	    std::cout << "Dropping irrelevant solution ";
 	    s2.dump(std::cout);
 	    std::cout << std::endl;
 	  }
 
-	open.push(s2);
+	return false;
+      }
+    else if(is_forbidden(s2))
+      {
+	if(debug)
+	  {
+	    std::cout << "Deferring forbidden solution ";
+	    s2.dump(std::cout);
+	    std::cout << std::endl;
+	  }
 
-	return true;
+	deferred.insert(s2);
+	return false;
       }
     else
       {
 	if(debug)
 	  {
-	    std::cout << "Dropping irrelevant solution ";
+	    std::cout << "Enqueuing ";
 	    s2.dump(std::cout);
 	    std::cout << std::endl;
 	  }
 
-	return false;
+	open.push(s2);
+
+	return true;
       }
   }
 
@@ -1094,7 +1189,7 @@
     :step_score(_step_score), broken_score(_broken_score),
      minimum_score(-infinity), max_successors(_max_successors),
      full_solution_score(_full_solution_score),
-     universe(_universe), finished(false), debug(false)
+     universe(_universe), finished(false), forbiddings_dirty(false), debug(false)
   {
     version_scores=new int[universe.get_version_count()];
     for(size_t i=0; i<universe.get_version_count(); ++i)
@@ -1180,6 +1275,30 @@
     return version_scores[ver.get_id()];
   }
 
+  /** Forbid this resolver from generating solutions containing the
+   *  given version.
+   */
+  void forbid_version(const version &ver)
+  {
+    user_forbidden.insert(ver);
+  }
+
+  /** Cancel any forbidding of ver, allowing the resolver to once
+   *  again generate solutions containing it.
+   */
+  void unforbid_version(const version &ver)
+  {
+    user_forbidden.erase(ver);
+
+    forbiddings_dirty = true;
+  }
+
+  /** Query whether the given version is forbidden. */
+  bool is_forbidden(const version &ver) const
+  {
+    return user_forbidden.find(ver) != user_forbidden.end();
+  }
+
   /** Try to find the "next" solution: remove partial solutions from
    *  the open queue and place them in the closed queue until one of
    *  the following occurs:
@@ -1205,6 +1324,9 @@
    */
   solution find_next_solution(int max_steps)
   {
+    if(forbiddings_dirty)
+      reexamine_deferred();
+
     if(finished)
       throw NoMoreSolutions();
 
@@ -1240,6 +1362,19 @@
 	    continue;
 	  }
 
+	if(is_forbidden(s))
+	  {
+	    if(debug)
+	      {
+		std::cout << "Deferring forbidden solution ";
+		s.dump(std::cout);
+		std::cout << std::endl;
+	      }
+
+	    deferred.insert(s);
+	    continue;
+	  }
+
 	closed.insert(s);
 
 	if(debug)



More information about the Aptitude-svn-commit mailing list