[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.