[Aptitude-devel] r3034 - in branches/aptitude-0.3/aptitude: . src/generic

Daniel Burrows dburrows@costa.debian.org
Fri, 22 Apr 2005 02:30:04 +0000


Author: dburrows
Date: Fri Apr 22 02:30:01 2005
New Revision: 3034

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/generic/aptcache.cc
   branches/aptitude-0.3/aptitude/src/generic/aptcache.h
Log:
Add support for maintaining and caching a set of known solutions to
extant problems.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Fri Apr 22 02:30:01 2005
@@ -1,5 +1,10 @@
 2005-04-21  Daniel Burrows  <dburrows@debian.org>
 
+	* src/generic/aptcache.cc, src/generic/aptcache.h:
+
+	  Write rudimentary code for maintaining a set of known solutions
+	  to any extant problems (expanded on demand).
+
 	* src/generic/problemresolver/problemresolver.h:
 
 	  Add a function that returns "true" if the open queue has been

Modified: branches/aptitude-0.3/aptitude/src/generic/aptcache.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/aptcache.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/aptcache.cc	Fri Apr 22 02:30:01 2005
@@ -1,6 +1,6 @@
 // aptcache.cc
 //
-//  Copyright 1999,2000,2001,2002 Daniel Burrows
+//  Copyright 1999-2005 Daniel Burrows
 //
 //  This program is free software; you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -19,12 +19,13 @@
 
 #include "../aptitude.h"
 
+#include "apt.h"
 #include "aptcache.h"
+#include "aptitude_resolver.h"
 #include "aptitudepolicy.h"
-#include "undo.h"
 #include "config_signal.h"
-#include "apt.h"
 #include "matchers.h"
+#include "undo.h"
 
 #include <apt-pkg/error.h>
 #include <apt-pkg/sourcelist.h>
@@ -164,7 +165,8 @@
 
 aptitudeDepCache::aptitudeDepCache(pkgCache *Cache, Policy *Plcy)
   :pkgDepCache(Cache, Plcy), dirty(false), package_states(NULL), lock(-1),
-   group_level(0), mark_and_sweep_in_progress(false)
+   group_level(0), mark_and_sweep_in_progress(false),
+   resolver(NULL), out_of_time(false), selected_solution(0)
 {
   // When the "install recommended packages" flag changes, collect garbage.
   aptcfg->connect(PACKAGE "::Recommends-Important",
@@ -187,6 +189,12 @@
 aptitudeDepCache::~aptitudeDepCache()
 {
   delete[] package_states;
+
+  for(unsigned int i=0; i<solutions.size(); ++i)
+    delete solutions[i];
+
+  delete resolver;
+
   if(lock!=-1)
     close(lock);
 }
@@ -648,7 +656,12 @@
   // Finds any packages whose states have changed and: (a) updates the
   // selected_state if it's not already updated; (b) adds an item to the
   // undo group.
+  //
+  // Also handles (since any change invalidates partial solutions)
+  // destroying and recreating (if necessary) a problem resolver.
 {
+  discard_resolver(undo);
+
   for(pkgCache::PkgIterator pkg=PkgBegin(); !pkg.end(); pkg++)
     {
       if(PkgState[pkg->ID].Mode!=backup_state.PkgState[pkg->ID].Mode ||
@@ -717,6 +730,9 @@
 					  backup_state.AptitudeState[pkg->ID]));
 	}
     }
+
+  if((*apt_cache_file)->BrokenCount()>0)
+    create_resolver();
 }
 
 void aptitudeDepCache::internal_mark_install(const PkgIterator &Pkg,
@@ -1291,6 +1307,108 @@
   end_action_group(undo);
 }
 
+////////////////// PROBLEM RESOLVER INTERFACE FOLLOWS //////////////////
+
+void aptitudeDepCache::discard_resolver(undo_group *undo)
+{
+  delete resolver;
+  solutions.clear();
+  resolver=NULL;
+  out_of_time=false;
+}
+
+void aptitudeDepCache::create_resolver()
+{
+  assert(resolver==NULL);
+
+  resolver=new aptitude_resolver(aptcfg->FindI(PACKAGE "::ProblemResolver::StepPenalty", 10),
+				 aptcfg->FindI(PACKAGE "::ProblemResolver::BrokenPenalty", 50));
+
+  resolver->add_action_scores(aptcfg->FindI(PACKAGE "::ProblemResolver::PreserveManualScore", 50),
+			      aptcfg->FindI(PACKAGE "::ProblemResolver::PreserveAutoScore", 25),
+			      aptcfg->FindI(PACKAGE "::ProblemResolver::RemoveScore", -50),
+			      aptcfg->FindI(PACKAGE "::ProblemResolver::KeepScore", -10),
+			      aptcfg->FindI(PACKAGE "::ProblemResolver::InstallScore", -20),
+			      aptcfg->FindI(PACKAGE "::ProblemResolver::UpgradeScore", -15),
+			      aptcfg->FindI(PACKAGE "::ProblemResolver::NonDefaultScore", -40),
+			      aptcfg->FindI(PACKAGE "::ProblemResolver::EssentialRemoveScore", -100000));
+
+  resolver->add_priority_scores(aptcfg->FindI(PACKAGE "::ProblemResolver::ImportantScore", 5),
+				aptcfg->FindI(PACKAGE "::ProblemResolver::RequiredScore", 4),
+				aptcfg->FindI(PACKAGE "::ProblemResolver::StandardScore", 3),
+				aptcfg->FindI(PACKAGE "::ProblemResolver::OptionalScore", 1),
+				aptcfg->FindI(PACKAGE "::ProblemResolver::ExtraScore", -1));
+}
+
+bool aptitudeDepCache::resolver_exists() const
+{
+  return resolver != NULL;
+}
+
+bool aptitudeDepCache::solutions_exhausted() const
+{
+  return (!resolver) || (resolver->exhausted() &&
+			 (solutions.empty() ||
+			  selected_solution == solutions.size()-1));
+}
+
+bool aptitudeDepCache::solutions_at_start() const
+{
+  return solutions.empty() || selected_solution == 0;
+}
+
+const aptitude_resolver::solution &aptitudeDepCache::get_current_solution()
+{
+  assert(resolver);
+
+  if(out_of_time)
+    throw NoMoreTime();
+  else if(!solutions.empty())
+    return *solutions[selected_solution];
+  else
+    return next_solution();
+}
+
+const aptitude_resolver::solution &aptitudeDepCache::next_solution()
+{
+  if(solutions.empty())
+    {
+      try
+	{
+	  solutions.push_back(new aptitude_resolver::solution(resolver->find_next_solution(aptcfg->FindI(PACKAGE "::ProblemResolver::StepLimit", 10000))));
+	  out_of_time=false;
+	  return *solutions.back();
+	}
+      catch(NoMoreTime) {
+	out_of_time=true;
+	throw NoMoreTime();
+      }
+    }
+  else if(selected_solution<solutions.size()-1)
+    {
+      ++selected_solution;
+      return *solutions[selected_solution];
+    }
+  else
+    {
+      // otherwise weirdness is happening.
+      assert(!out_of_time);
+      solutions.push_back(new aptitude_resolver::solution(resolver->find_next_solution(aptcfg->FindI(PACKAGE "::ProblemResolver::StepLimit", 10000))));
+      return *solutions.back();
+    }
+}
+
+const aptitude_resolver::solution &aptitudeDepCache::previous_solution()
+{
+  if(solutions.empty() || selected_solution == 0)
+    throw NoMoreSolutions();
+
+  --selected_solution;
+  return *solutions[selected_solution];
+}
+
+//////////////////// END PROBLEM RESOLVER INTERFACE ////////////////////
+
 aptitudeCacheFile::aptitudeCacheFile()
   :Map(NULL), Cache(NULL), DCache(NULL), have_system_lock(false), Policy(NULL)
 {

Modified: branches/aptitude-0.3/aptitude/src/generic/aptcache.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/aptcache.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/aptcache.h	Fri Apr 22 02:30:01 2005
@@ -35,9 +35,13 @@
 #include <sigc++/signal.h>
 #include <sigc++/trackable.h>
 
+#include "problemresolver/problemresolver.h"
+
 class undoable;
 class undo_group;
 class pkgProblemResolver;
+class aptitude_resolver;
+class aptitude_universe;
 
 class aptitudeDepCache:public pkgDepCache, public sigc::trackable
 {
@@ -203,6 +207,40 @@
   apt_state_snapshot backup_state;
   // Stores what the cache was like just before an action was performed
 
+  /** The current problem resolver.  This is destroyed (if it exists)
+   *  in cleanup_after_change, then created again if broken packages
+   *  exist.
+   */
+  aptitude_resolver *resolver;
+
+  /** If \b true, there are no solutions and the last attempt to
+   *  calculate one failed with NoMoreTime.
+   *
+   *  This is used so that the return value of get_current_solution()
+   *  is stable.
+   */
+  bool out_of_time;
+
+  /** All the solutions generated since the last change to the cache.
+   */
+  std::vector<generic_solution<aptitude_universe> *> solutions;
+
+  /** The currently "selected" solution, as an index in the solutions
+   *  array.
+   */
+  unsigned int selected_solution;
+
+  /** Call whenever the cache state is modified; discards the
+   *  state of the active resolver.
+   *
+   *  \param undo the undo group with which this discarding should be
+   *  associated.
+   */
+  void discard_resolver(undo_group *undo);
+
+  /** Call whenever a new resolver should be instantiated. */
+  void create_resolver();
+
   undoable *state_restorer(PkgIterator pkg, StateCache &state, aptitude_state &ext_state);
   // Returns an 'undoable' object which will restore the given package to the
   // given state via {Mark,Set}* routines
@@ -324,6 +362,64 @@
   bool all_upgrade(bool with_autoinst, undo_group *undo);
   // Wrapper for pkgAllUpgrade (the engine of "apt-get upgrade")
 
+  /** If \b true, then a resolver has been created, indicating that
+      problems may exist.
+   */
+  bool resolver_exists() const;
+
+  /** If \b true, then either there is no resolver, or the resolver
+   *  has been exhausted and the solution pointer is set to the last
+   *  solution.
+   */
+  bool solutions_exhausted() const;
+
+  /** If \b true, the solution pointer is set to the first
+   *  solution.
+   */
+  bool solutions_at_start() const;
+
+  // NB: the reason for returning references below is because
+  // otherwise you have circular dependencies between code and nothing
+  // compiles :(
+
+  /** Requires that resolver_exists() is \b true.  If no solutions
+   *  have been calculated yet, will calculate and return the first
+   *  solution.
+   *
+   *  \return the currently selected solution.  This reference is not
+   *  guaranteed to persist if any other operation is performed on the
+   *  cache; a stack variable should be instantiated from it.
+   *
+   *  \throws NoMoreSolutions if there are no solutions and the search
+   *  is exhausted.
+   *
+   *  \throws NoMoreTime if there are no solutions and the last effort
+   *  ran out of time.
+   */
+  const generic_solution<aptitude_universe> &get_current_solution();
+
+  /** Advance to the next solution.
+   *
+   *  \return the next solution.  This reference is not guaranteed to
+   *  persist if any other operation is performed on the cache; a
+   *  stack variable should be instantiated from it.
+   *
+   *  \throws NoMoreSolutions if there are no more solutions
+   *  \throws NoMoreTime if a solution could not be found before the
+   *                     cutoff time expired.
+   */
+  const generic_solution<aptitude_universe> &next_solution();
+
+  /** Return to the previous solution.
+   *
+   *  \return the previous solution.  This reference is not guaranteed
+   *  to persist if any other operation is performed on the cache; a
+   *  stack variable should be instantiated from it.
+   *
+   *  \throws NoMoreSolutions if solutions_at_start()==0
+   */
+  const generic_solution<aptitude_universe> &previous_solution();
+
   bool try_fix_broken(undo_group *undo);
   // Attempts to fix any broken packages, dumping the changes the problem
   // fixer creates into the given undo group.