3
// Copyright (C) 2005, 2007-2010 Daniel Burrows
5
// This program is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU General Public License as
7
// published by the Free Software Foundation; either version 2 of
8
// the License, or (at your option) any later version.
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// General Public License for more details.
15
// You should have received a copy of the GNU General Public License
16
// along with this program; see the file COPYING. If not, write to
17
// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
// Boston, MA 02111-1307, USA.
20
#include "resolver_manager.h"
24
#include "aptitude_resolver.h"
25
#include "aptitude_resolver_cost_settings.h"
26
#include "aptitude_resolver_cost_syntax.h"
27
#include "aptitude_resolver_universe.h"
28
#include "config_signal.h"
29
#include "dump_packages.h"
31
#include <boost/format.hpp>
32
#include <boost/make_shared.hpp>
36
#include <generic/problemresolver/problemresolver.h>
37
#include <generic/util/temp.h>
38
#include <generic/util/undo.h>
40
#include <apt-pkg/error.h>
41
#include <apt-pkg/strutl.h>
43
#include <sigc++/bind.h>
44
#include <sigc++/functors/mem_fun.h>
48
#include <sys/types.h>
51
using aptitude::Loggers;
53
const int defaultStepLimit = 500000;
55
class resolver_manager::resolver_interaction
58
/** \brief The type tag of a resolver interaction. */
75
aptitude_resolver_version version;
76
aptitude_resolver_dep dep;
78
resolver_interaction(tag _type,
79
const aptitude_resolver_version &_version,
80
const aptitude_resolver_dep &_dep)
81
: type(_type), version(_version), dep(_dep)
86
static resolver_interaction RejectVersion(const aptitude_resolver_version &version)
88
return resolver_interaction(reject_version, version,
89
aptitude_resolver_dep());
92
static resolver_interaction UnRejectVersion(const aptitude_resolver_version &version)
94
return resolver_interaction(unreject_version, version,
95
aptitude_resolver_dep());
98
static resolver_interaction MandateVersion(const aptitude_resolver_version &version)
100
return resolver_interaction(mandate_version, version,
101
aptitude_resolver_dep());
104
static resolver_interaction UnMandateVersion(const aptitude_resolver_version &version)
106
return resolver_interaction(unmandate_version, version,
107
aptitude_resolver_dep());
110
static resolver_interaction HardenDep(const aptitude_resolver_dep &dep)
112
return resolver_interaction(harden_dep,
113
aptitude_resolver_version(),
117
static resolver_interaction UnHardenDep(const aptitude_resolver_dep &dep)
119
return resolver_interaction(unharden_dep,
120
aptitude_resolver_version(),
124
static resolver_interaction ApproveBrokenDep(const aptitude_resolver_dep &dep)
126
return resolver_interaction(approve_broken_dep,
127
aptitude_resolver_version(),
131
static resolver_interaction UnApproveBrokenDep(const aptitude_resolver_dep &dep)
133
return resolver_interaction(unapprove_broken_dep,
134
aptitude_resolver_version(),
138
static resolver_interaction Undo()
140
return resolver_interaction(undo,
141
aptitude_resolver_version(),
142
aptitude_resolver_dep());
145
tag get_type() const { return type; }
146
const aptitude_resolver_version &get_version() const
148
eassert(!version.get_pkg().end());
151
const aptitude_resolver_dep &get_dep() const
153
eassert(!dep.get_dep().end());
158
resolver_manager::solution_information::~solution_information()
164
// NB: we need a recursive mutex because some routines can be called
165
// either by other routines of the class (already have a mutex lock)
166
// or by the user (don't have a mutex lock); I could sidestep this
167
// with some clever magic, but there's no point unless it turns out to
169
resolver_manager::resolver_manager(aptitudeCacheFile *_cache_file,
170
const imm::map<aptitude_resolver_package, aptitude_resolver_version> &_initial_installations)
171
:cache_file(_cache_file),
173
undos(new undo_list),
174
ticks_since_last_solution(0),
175
solution_search_aborted(false),
176
selected_solution(0),
177
background_thread_killed(false),
178
background_thread_running(false),
180
background_thread_suspend_count(0),
181
background_thread_in_resolver(false),
182
initial_installations(_initial_installations),
183
resolver_thread(NULL),
184
mutex(cwidget::threads::mutex::attr(PTHREAD_MUTEX_RECURSIVE))
186
(*cache_file)->pre_package_state_changed.connect(sigc::mem_fun(this, &resolver_manager::discard_resolver));
187
(*cache_file)->package_state_changed.connect(sigc::mem_fun(this, &resolver_manager::maybe_create_resolver));
189
aptcfg->connect("Apt::Install-Recommends",
191
&resolver_manager::discard_resolver));
193
start_background_thread();
195
maybe_create_resolver();
198
resolver_manager::~resolver_manager()
200
eassert(background_thread_running);
204
kill_background_thread();
206
for(std::vector<const solution_information *>::const_iterator it =
207
solutions.begin(); it != solutions.end(); ++it)
215
void resolver_manager::reset_resolver()
218
maybe_create_resolver();
221
resolver_manager::background_continuation::~background_continuation()
225
class resolver_manager::background_suspender
231
background_suspender(resolver_manager &_m)
232
:m(_m), suspended(true)
234
m.suspend_background_thread();
241
m.unsuspend_background_thread();
246
~background_suspender()
249
m.unsuspend_background_thread();
253
/** A class that assigns a value to an object when it is destroyed.
256
class set_when_destroyed
262
/** Create a set_when_destroyed.
264
* \param _target The object to be set.
265
* \param _val The value to assign to _target.
267
set_when_destroyed(T &_target, const T &_val)
268
: target(_target), val(_val)
272
/** Assign val to target. */
273
~set_when_destroyed()
279
void resolver_manager::write_test_control_file(const std::string &outDir,
280
const std::set<aptitude_resolver_package> &visited_packages,
283
static const char * const strBadChars = "\\\"";
285
std::string control_filename = outDir + "/APTITUDE.TRACE";
286
std::ofstream control_file(control_filename.c_str());
288
return; // Should we output an error here?
290
// The state files are written out in make_truncated_state_copy.
291
// Here we just indicate the actual installs / removals that are
294
control_file << "initial {" << std::endl;
295
for(std::set<aptitude_resolver_package>::const_iterator
296
it = visited_packages.begin();
297
it != visited_packages.end();
300
const aptitude_resolver_package &p(*it);
301
if(visited_packages.find(p) == visited_packages.end())
304
pkg_action_state action = find_pkg_state(p.get_pkg(), **cache_file);
305
std::string actionstr;
308
case pkg_unused_remove:
309
case pkg_auto_remove:
311
actionstr = "remove";
314
case pkg_auto_install:
318
actionstr = std::string("install ") +
319
(*cache_file)[p.get_pkg()].InstVerIter(*cache_file).VerStr();
326
if(!actionstr.empty())
327
control_file << " " << actionstr << " \"" << QuoteString(p.get_name(), strBadChars) << "\"" << std::endl;;
330
control_file << "}" << std::endl;
331
control_file << std::endl;
334
cwidget::threads::mutex::lock sol_l(solutions_mutex);
336
for(std::vector<const solution_information *>::const_iterator infIt =
338
infIt != solutions.end() && infIt - solutions.begin() <= solution_number;
341
control_file << "test {" << std::endl;
343
const solution_information &inf = **infIt;
344
const std::vector<resolver_interaction> &acts =
345
*inf.get_interactions();
346
const generic_solution<aptitude_universe> &sol = *inf.get_solution();
348
for(std::vector<resolver_interaction>::const_iterator actIt =
349
acts.begin(); actIt != acts.end(); ++actIt)
351
switch(actIt->get_type())
353
case resolver_interaction::reject_version:
354
control_file << "reject " << actIt->get_version() << std::endl;
356
case resolver_interaction::unreject_version:
357
control_file << "unreject " << actIt->get_version() << std::endl;
359
case resolver_interaction::mandate_version:
360
control_file << "mandate " << actIt->get_version() << std::endl;
362
case resolver_interaction::unmandate_version:
363
control_file << "unmandate " << actIt->get_version() << std::endl;
365
case resolver_interaction::harden_dep:
366
control_file << "harden " << actIt->get_dep() << std::endl;
368
case resolver_interaction::unharden_dep:
369
control_file << "unharden " << actIt->get_dep() << std::endl;
371
case resolver_interaction::approve_broken_dep:
372
control_file << "approve_broken " << actIt->get_dep() << std::endl;
374
case resolver_interaction::unapprove_broken_dep:
375
control_file << "unapprove_broken " << actIt->get_dep() << std::endl;
377
case resolver_interaction::undo:
378
control_file << "undo" << std::endl;
383
control_file << " expect " << inf.get_ticks() << " {" << std::endl;
385
typedef generic_choice_set<aptitude_universe> choice_set;
386
typedef generic_choice<aptitude_universe> choice;
387
typedef aptitude_resolver_package package;
388
typedef aptitude_resolver_version version;
389
typedef aptitude_resolver_dep dep;
390
const choice_set &choices = sol.get_choices();
391
for(choice_set::const_iterator solChoiceIt =
392
choices.begin(); solChoiceIt != choices.end(); ++solChoiceIt)
394
switch(solChoiceIt->get_type())
396
case choice::install_version:
397
control_file << " install \""
398
<< QuoteString(solChoiceIt->get_ver().get_package().get_name(), strBadChars)
400
<< QuoteString(solChoiceIt->get_ver().get_name(), strBadChars)
405
case choice::break_soft_dep:
407
dep d(solChoiceIt->get_dep());
408
version source(d.get_source());
410
control_file << " break \""
411
<< QuoteString(source.get_package().get_name(), strBadChars)
413
<< QuoteString(source.get_name(), strBadChars)
417
for(dep::solver_iterator sIt = d.solvers_begin();
423
control_file << ", ";
425
version solver(*sIt);
427
<< QuoteString(solver.get_package().get_name(), strBadChars)
429
<< QuoteString(solver.get_name(), strBadChars)
433
control_file << "}" << std::endl;
439
// ... recover sanely.
440
control_file << "ERROR" << std::endl;
443
control_file << " }" << std::endl;
445
control_file << "}" << std::endl;
450
void resolver_manager::dump_visited_packages(const std::set<aptitude_resolver_package> &visited_packages,
453
std::string trace_dir;
454
temp::dir temp_trace_dir;
455
if(!resolver_trace_dir.empty())
456
trace_dir = resolver_trace_dir;
457
else if(!resolver_trace_file.empty())
459
temp_trace_dir = temp::dir("aptitude-trace-dump");
460
trace_dir = temp_trace_dir.get_name();
465
std::set<pkgCache::PkgIterator> packages;
466
for(std::set<aptitude_resolver_package>::const_iterator it = visited_packages.begin();
467
it != visited_packages.end(); ++it)
469
packages.insert((*it).get_pkg());
472
aptitude::apt::make_truncated_state_copy(trace_dir, packages);
473
write_test_control_file(trace_dir, visited_packages, solution_number);
475
if(!resolver_trace_file.empty())
479
_error->Errno("fork", "Unable to run \"tar\" to create the trace file.");
483
while(waitpid(pid, &status, 0) != pid ||
484
(!WIFEXITED(status) &&
485
!WIFSIGNALED(status)))
488
if(WIFSIGNALED(status))
489
_error->Error(_("Unable to create the output file: child killed by signal %d."), WTERMSIG(status));
490
else if(WEXITSTATUS(status) != 0)
491
_error->Error(_("Unable to create the output file: child exited with status %d."), WEXITSTATUS(status));
497
// Should I close open fds here?
499
// Should I allow tar to be found on the path?
500
execl("/bin/tar", "/bin/tar", "czf",
501
resolver_trace_file.c_str(),
507
// TODO: communicate to the parent that we couldn't find
516
// Trampoline used to invoke continuations directly in the
517
// background thread (where it's OK to do so).
518
void inline_continuation_trampoline(const sigc::slot<void> &f)
524
// This assumes that background_resolver_active is empty when it
525
// starts (see restart_background_resolver)
527
// FIXME: max_steps should be changed when the configuration is (not a
528
// visible bug at the moment since you can't change that option
530
void resolver_manager::background_thread_execution()
532
logging::LoggerPtr logger = Loggers::getAptitudeResolverThread();
533
LOG_TRACE(logger, "Resolver thread: starting.");
534
std::set<aptitude_resolver_package> visited_packages;
536
cwidget::threads::mutex::lock l(background_control_mutex);
537
set_when_destroyed<bool> cancel_set_running(background_thread_running, false);
541
while((background_thread_suspend_count > 0 || resolver_null || pending_jobs.empty()) &&
542
!background_thread_killed)
544
if(logger->isEnabledFor(logging::TRACE_LEVEL))
546
std::vector<std::string> why_suspended;
547
if(background_thread_suspend_count > 0)
548
why_suspended.push_back("waiting to be unsuspended");
550
why_suspended.push_back("waiting for a resolver to be created");
551
if(pending_jobs.empty())
552
why_suspended.push_back("waiting for a job");
554
if(!why_suspended.empty())
557
for(std::vector<std::string>::const_iterator it = why_suspended.begin();
558
it != why_suspended.end(); ++it)
565
LOG_TRACE(logger, "Resolver thread: " << msg << ".");
569
background_control_cond.wait(l);
572
if(background_thread_killed)
574
LOG_TRACE(logger, "Resolver thread: exiting (killed).");
578
job_request job = pending_jobs.top();
582
"Resolver thread: got a new job { solution number = "
583
<< job.sol_num << ", max steps = " << job.max_steps
584
<< ", continuation = " << job.k << " }");
586
background_thread_in_resolver = true;
587
background_resolver_cond.wake_all();
592
const aptitude_resolver::solution *sol =
593
do_get_solution(job.max_steps,
598
"Resolver thread: got a solution: " << *sol);
600
// Set the state variable BEFORE exiting the resolver; this
601
// is done so that if there are no more jobs, the foreground
602
// thread sees that we're out of the resolver when it
603
// examines the solution.
605
dump_visited_packages(visited_packages,
607
background_thread_in_resolver = false;
608
background_resolver_cond.wake_all();
611
// A slot that invokes job.k->success(*sol):
612
sigc::slot<void> success_slot =
613
sigc::bind(sigc::mem_fun(*job.k,
614
&background_continuation::success),
616
// Wrap a keepalive slot around that so job.k lives.
617
job.post_thunk(make_keepalive_slot(success_slot, job.k));
619
catch(InterruptedException)
621
// Put it back into the pot.
625
"Resolver thread: interrupted, pushing a job back on the queue "
626
<< "{ solution number = " << job.sol_num
627
<< ", max_steps = " << job.max_steps
628
<< ", continuation = " << job.k << "}");
630
dump_visited_packages(visited_packages,
632
background_thread_in_resolver = false;
633
background_resolver_cond.wake_all();
634
pending_jobs.push(job);
638
catch(NoMoreSolutions)
643
"Resolver thread: out of solutions.");
645
dump_visited_packages(visited_packages,
647
background_thread_in_resolver = false;
648
background_resolver_cond.wake_all();
651
sigc::slot<void> no_more_solutions_slot =
652
sigc::mem_fun(*job.k,
653
&background_continuation::no_more_solutions);
654
job.post_thunk(make_keepalive_slot(no_more_solutions_slot, job.k));
661
"Resolver thread: out of time.");
663
dump_visited_packages(visited_packages,
665
background_thread_in_resolver = false;
666
background_resolver_cond.wake_all();
669
sigc::slot<void> no_more_time_slot =
670
sigc::mem_fun(*job.k,
671
&background_continuation::no_more_time);
672
job.post_thunk(make_keepalive_slot(no_more_time_slot, job.k));
674
catch(cwidget::util::Exception &e)
677
"Resolver thread: caught a fatal error from the resolver: "
680
dump_visited_packages(visited_packages,
683
sigc::slot<void> aborted_slot =
684
sigc::bind(sigc::mem_fun(*job.k,
685
&background_continuation::aborted),
687
job.post_thunk(make_keepalive_slot(aborted_slot, job.k));
692
background_thread_in_resolver = false;
693
background_resolver_cond.wake_all();
697
// Need this because sigc slots aren't threadsafe :-(
698
struct resolver_manager::background_thread_bootstrap
702
background_thread_bootstrap(resolver_manager &_m)
709
m.background_thread_execution();
713
void resolver_manager::start_background_thread()
715
cwidget::threads::mutex::lock l(mutex);
717
if(resolver_thread == NULL)
719
background_thread_running = true;
720
resolver_thread = new cwidget::threads::thread(background_thread_bootstrap(*this));
724
void resolver_manager::kill_background_thread()
726
cwidget::threads::mutex::lock l(mutex);
728
if(resolver_thread != NULL)
730
cwidget::threads::mutex::lock control_lock(background_control_mutex);
733
resolver->cancel_solver();
734
background_thread_killed = true;
735
background_control_cond.wake_all();
737
control_lock.release();
739
resolver_thread->join();
740
delete resolver_thread;
741
resolver_thread = NULL;
744
// Reset the associated data structures.
745
control_lock.acquire();
746
pending_jobs = std::priority_queue<job_request, std::vector<job_request>, job_request_compare>();
747
background_thread_killed = false;
748
background_thread_suspend_count = 0;
749
background_thread_in_resolver = false;
750
solution_search_aborted = false;
751
solution_search_abort_msg.clear();
755
void resolver_manager::suspend_background_thread()
757
cwidget::threads::mutex::lock l(mutex);
759
// May occur due to background_suspend objects existing while
760
// kill_background_thread runs.
761
if(resolver_thread == NULL)
764
cwidget::threads::mutex::lock control_lock(background_control_mutex);
767
resolver->cancel_solver();
769
++background_thread_suspend_count;
770
background_control_cond.wake_all();
772
while(background_thread_in_resolver)
773
background_resolver_cond.wait(control_lock);
776
resolver->uncancel_solver();
779
void resolver_manager::unsuspend_background_thread()
781
cwidget::threads::mutex::lock l(mutex);
783
if(resolver_thread == NULL)
786
cwidget::threads::mutex::lock control_lock(background_control_mutex);
788
eassert(background_thread_suspend_count > 0);
789
--background_thread_suspend_count;
790
background_control_cond.wake_all();
793
void resolver_manager::maybe_create_resolver()
795
cwidget::threads::mutex::lock l(mutex);
797
if(resolver == NULL && ((*cache_file)->BrokenCount() > 0 || !initial_installations.empty()))
800
cwidget::threads::mutex::lock l(background_control_mutex);
801
resolver_trace_dir = aptcfg->Find(PACKAGE "::ProblemResolver::Trace-Directory", "");
802
resolver_trace_file = aptcfg->Find(PACKAGE "::ProblemResolver::Trace-File", "");
806
// If there are initial installations, we don't know whether
807
// there are broken dependencies until we actually create the
808
// resolver. If there aren't broken dependencies, don't create
809
// a resolver object.
810
if(resolver->get_initial_broken().empty())
814
// Always signal a state change: we are signalling for the whole
815
// discard/create pair, and even if we didn't create a new resolver
816
// we have to inform the listeners that the old one went away
822
void resolver_manager::discard_resolver()
824
cwidget::threads::mutex::lock l(mutex);
829
background_suspender bs(*this);
831
undos->clear_items();
836
cwidget::threads::mutex::lock l2(solutions_mutex);
837
actions_since_last_solution.clear();
838
ticks_since_last_solution = 0;
840
for(std::vector<const solution_information *>::const_iterator it =
841
solutions.begin(); it != solutions.end(); ++it)
845
solution_search_aborted = false;
846
solution_search_abort_msg.clear();
847
selected_solution = 0;
853
cwidget::threads::mutex::lock l2(background_control_mutex);
854
resolver_null = true;
855
pending_jobs = std::priority_queue<job_request, std::vector<job_request>, job_request_compare>();
856
background_control_cond.wake_all();
860
void resolver_manager::create_resolver()
862
cwidget::threads::mutex::lock l(mutex);
863
eassert(resolver == NULL);
865
// \todo We should parse these once on startup to avoid duplicate
866
// error messages, support modifying the list dynamically (for the
867
// sake of GUI users), etc.
868
std::vector<aptitude_resolver::hint> hints;
870
const Configuration::Item * const root =
871
aptcfg->Tree(PACKAGE "::ProblemResolver::Hints");
875
for(const Configuration::Item *itm = root->Child;
876
itm != NULL; itm = itm -> Next)
878
aptitude_resolver::hint hint;
879
if(aptitude_resolver::hint::parse(itm->Value, hint))
880
hints.push_back(hint);
884
// NOTE: the performance of the resolver is highly sensitive to
885
// these settings; choosing bad ones can result in hitting
886
// exponential cases in practical situations. In general,
887
// penalizing actions means that the resolver will be more likely to
888
// blow up trying to avoid them, with the danger increasing as the
889
// penalty does. Thus, aside from broken deps (which are penalized
890
// to guide us towards a solution), I only penalize removals (which
891
// are usually either unnecessary or easy to prove necessary) and
892
// leaving soft dependencies (recommendations) unfixed. The
893
// relative penalties of these are also important; for instance,
894
// penalizing unfixed soft deps more than removals means that the
895
// resolver will actually remove packages rather than leaving their
896
// Recommends: field unsatisfied!
899
std::string cost_configuration = aptcfg->Find(PACKAGE "::ProblemResolver::SolutionCost",
902
boost::shared_ptr<std::vector<cost_component_structure> > cost_components;
905
cost_components = parse_cost_settings(cost_configuration);
907
catch(ResolverCostParseException &ex)
909
LOG_ERROR(Loggers::getAptitudeResolver(),
910
boost::format(_("Failed to parse the cost settings string: %s")) % ex.what());
912
_error->Error(_("Failed to parse the cost settings string: %s"),
915
// Fall back to a default cost settings list containing the
916
// "safety" and "priority" components.
917
cost_components = boost::make_shared<std::vector<cost_component_structure> >();
919
std::vector<cost_component_structure::entry> level0;
920
level0.push_back(cost_component_structure::entry("safety", 1));
921
cost_components->push_back(cost_component_structure(cost_component_structure::combine_none, level0));
923
std::vector<cost_component_structure::entry> level1;
924
level1.push_back(cost_component_structure::entry("priority", 1));
925
cost_components->push_back(cost_component_structure(cost_component_structure::combine_none, level1));
929
aptitude_resolver_cost_settings cost_settings(cost_components);
932
cost ignored_recommends_cost;
934
aptitude_resolver_cost_settings::component ignored_recommends_component =
935
cost_settings.get_or_create_component("ignored-recommends", aptitude_resolver_cost_settings::additive);
936
ignored_recommends_cost = cost_settings.add_to_cost(ignored_recommends_component, 1);
939
resolver=new aptitude_resolver(aptcfg->FindI(PACKAGE "::ProblemResolver::StepScore", 70),
940
aptcfg->FindI(PACKAGE "::ProblemResolver::BrokenScore", -100),
941
aptcfg->FindI(PACKAGE "::ProblemResolver::UnfixedSoftScore", -200),
942
aptcfg->FindI(PACKAGE "::ProblemResolver::Infinity", 1000000),
943
aptcfg->FindI(PACKAGE "::ProblemResolver::ResolutionScore", 50),
944
ignored_recommends_cost,
945
aptcfg->FindI(PACKAGE "::ProblemResolver::FutureHorizon", 50),
947
initial_installations,
951
// Set auto flags for initial installations as if the installs were
952
// done by the user. i.e., if the package is currently installed,
953
// we use the current value of the Auto flag; otherwise we treat it
955
std::map<aptitude_resolver_package, bool> manual_flags;
956
for(imm::map<aptitude_resolver_package, aptitude_resolver_version>::const_iterator it =
957
initial_installations.begin(); it != initial_installations.end(); ++it)
959
pkgCache::PkgIterator pkg(it->first.get_pkg());
960
aptitude_resolver_package resolver_pkg(pkg, *cache_file);
962
if(pkg->CurrentState != pkgCache::State::NotInstalled &&
963
pkg->CurrentState != pkgCache::State::ConfigFiles)
965
manual_flags[resolver_pkg] =
966
((*cache_file)[pkg].Flags & pkgCache::Flag::Auto) == 0;
968
LOG_DEBUG(Loggers::getAptitudeResolverInitialManualFlags(),
969
"Set the manual flag for the currently installed package "
970
<< resolver_pkg << " to "
971
<< (manual_flags[resolver_pkg] ? "true" : "false")
972
<< " to reflect its current auto flag.");
976
manual_flags[resolver_pkg] = true;
977
LOG_DEBUG(Loggers::getAptitudeResolverInitialManualFlags(),
978
"Set the manual flag for the non-installed package "
979
<< resolver_pkg << " to "
980
<< (manual_flags[resolver_pkg] ? "true" : "false"));
984
resolver->add_action_scores(aptcfg->FindI(PACKAGE "::ProblemResolver::PreserveManualScore", 60),
985
aptcfg->FindI(PACKAGE "::ProblemResolver::PreserveAutoScore", 0),
986
aptcfg->FindI(PACKAGE "::ProblemResolver::RemoveScore", -300),
987
aptcfg->FindI(PACKAGE "::ProblemResolver::KeepScore", 0),
988
aptcfg->FindI(PACKAGE "::ProblemResolver::InstallScore", -20),
989
aptcfg->FindI(PACKAGE "::ProblemResolver::UpgradeScore", 0),
990
aptcfg->FindI(PACKAGE "::ProblemResolver::NonDefaultScore", -40),
991
aptcfg->FindI(PACKAGE "::ProblemResolver::EssentialRemoveScore", -100000),
992
aptcfg->FindI(PACKAGE "::ProblemResolver::FullReplacementScore", 500),
993
aptcfg->FindI(PACKAGE "::ProblemResolver::UndoFullReplacementScore", -500),
994
aptcfg->FindI(PACKAGE "::ProblemResolver::BreakHoldScore", -300),
995
aptcfg->FindB(PACKAGE "::ProblemResolver::Allow-Break-Holds", false),
996
aptcfg->FindI(PACKAGE "::ProblemResolver::DefaultResolutionScore", 400),
1000
resolver->add_priority_scores(aptcfg->FindI(PACKAGE "::ProblemResolver::ImportantScore", 5),
1001
aptcfg->FindI(PACKAGE "::ProblemResolver::RequiredScore", 4),
1002
aptcfg->FindI(PACKAGE "::ProblemResolver::StandardScore", 3),
1003
aptcfg->FindI(PACKAGE "::ProblemResolver::OptionalScore", 1),
1004
aptcfg->FindI(PACKAGE "::ProblemResolver::ExtraScore", -1));
1007
cwidget::threads::mutex::lock l2(background_control_mutex);
1008
resolver_null = false;
1009
background_control_cond.wake_all();
1013
void resolver_manager::set_resolver_trace_dir(const std::string &path)
1015
cwidget::threads::mutex::lock l(background_control_mutex);
1016
resolver_trace_dir = path;
1019
void resolver_manager::set_debug(bool activate)
1021
cwidget::threads::mutex::lock l(mutex);
1022
background_suspender bs(*this);
1024
eassert(resolver_exists());
1026
resolver->set_debug(activate);
1029
bool resolver_manager::resolver_exists() const
1031
cwidget::threads::mutex::lock l(mutex);
1033
return resolver != NULL;
1036
unsigned int resolver_manager::generated_solution_count() const
1038
cwidget::threads::mutex::lock l(mutex);
1039
cwidget::threads::mutex::lock l2(solutions_mutex);
1041
return solutions.size();
1044
bool resolver_manager::solution_generation_complete() // const
1046
return state_snapshot().solutions_exhausted;
1049
bool resolver_manager::solutions_at_start() const
1051
cwidget::threads::mutex::lock l(mutex);
1053
if(!resolver_exists())
1056
return selected_solution == 0;
1059
bool resolver_manager::background_thread_active()
1061
cwidget::threads::mutex::lock l(mutex);
1063
cwidget::threads::mutex::lock ctl_l(background_control_mutex);
1065
return !pending_jobs.empty() || background_thread_in_resolver;
1068
bool resolver_manager::background_thread_aborted()
1070
cwidget::threads::mutex::lock l(mutex);
1072
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1074
return solution_search_aborted;
1077
std::string resolver_manager::background_thread_abort_msg()
1079
cwidget::threads::mutex::lock l(mutex);
1081
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1083
return solution_search_aborted ? solution_search_abort_msg : "";
1086
resolver_manager::state resolver_manager::state_snapshot()
1088
cwidget::threads::mutex::lock l(mutex);
1090
cwidget::threads::mutex::lock ctl_l(background_control_mutex);
1092
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1096
rval.selected_solution = selected_solution;
1097
rval.generated_solutions = solutions.size();
1098
rval.resolver_exists = (resolver != NULL);
1099
rval.background_thread_active = !solution_search_aborted &&
1100
(!pending_jobs.empty() ||
1101
background_thread_in_resolver);
1102
rval.background_thread_aborted = solution_search_aborted;
1103
rval.background_thread_abort_msg = solution_search_abort_msg;
1105
if(resolver != NULL)
1107
aptitude_resolver::queue_counts c = resolver->get_counts();
1109
rval.open_size = c.open;
1110
rval.closed_size = c.closed;
1111
rval.deferred_size = c.deferred;
1112
rval.conflicts_size = c.conflicts;
1113
rval.solutions_exhausted = c.finished;
1118
rval.closed_size = 0;
1119
rval.deferred_size = 0;
1120
rval.conflicts_size = 0;
1122
rval.solutions_exhausted = false;
1128
const aptitude_resolver::solution *
1129
resolver_manager::do_get_solution(int max_steps, unsigned int solution_num,
1130
std::set<aptitude_resolver_package> &visited_packages)
1132
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1133
if(solution_num < solutions.size())
1134
return solutions[solution_num]->get_solution();
1136
while(solution_num >= solutions.size())
1142
generic_solution<aptitude_universe> sol = resolver->find_next_solution(max_steps, &visited_packages);
1146
bool is_keep_all_solution =
1147
(sol.get_choices() == resolver->get_keep_all_solution());
1149
solutions.push_back(new solution_information(new std::vector<resolver_interaction>(actions_since_last_solution),
1150
ticks_since_last_solution + max_steps,
1151
new aptitude_resolver::solution(sol.clone()),
1152
is_keep_all_solution));
1153
actions_since_last_solution.clear();
1156
catch(const InterruptedException &e)
1158
ticks_since_last_solution += e.get_steps();
1163
ticks_since_last_solution += max_steps;
1166
catch(NoMoreSolutions)
1168
throw NoMoreSolutions();
1170
catch(cwidget::util::Exception &e)
1173
solution_search_aborted = true;
1174
solution_search_abort_msg = e.errmsg();
1179
return solutions[solution_num]->get_solution();
1182
/** A continuation that works by either placing \b true in the Boolean
1183
* variable corresponding to the thrown exception, or updating the
1184
* given solution, then signalling the given condition. If the
1185
* search terminated with an exception, we set the output solution to
1186
* NULL and set abort_msg to the exception's description.
1188
class solution_return_continuation : public resolver_manager::background_continuation
1190
const generic_solution<aptitude_universe> * /
1191
std::string &abort_msg;
1194
cwidget::threads::mutex &m;
1195
cwidget::threads::condition &c;
1197
solution_return_continuation(const generic_solution<aptitude_universe> * &_sol,
1198
std::string &_abort_msg,
1201
cwidget::threads::mutex &_m,
1202
cwidget::threads::condition &_c)
1203
:sol(_sol), abort_msg(_abort_msg), oot(_oot), oos(_oos), m(_m), c(_c)
1207
void success(const generic_solution<aptitude_universe> &result)
1209
cwidget::threads::mutex::lock l(m);
1217
cwidget::threads::mutex::lock l(m);
1223
void no_more_solutions()
1225
cwidget::threads::mutex::lock l(m);
1232
// Should never happen, since we hold the big lock.
1236
void aborted(const std::string &errmsg)
1238
cwidget::threads::mutex::lock l(m);
1246
/** \brief Sadly, we can't easily save the real exception and reuse it
1249
class SolutionSearchAbortException : public cwidget::util::Exception
1254
SolutionSearchAbortException(const std::string &_msg)
1259
std::string errmsg() const
1265
const aptitude_resolver::solution &resolver_manager::get_solution(unsigned int solution_num,
1268
cwidget::threads::mutex::lock l(mutex);
1273
cwidget::threads::mutex::lock l2(solutions_mutex);
1274
if(solution_num < solutions.size())
1275
return *solutions[solution_num]->get_solution();
1279
const generic_solution<aptitude_universe> *sol = NULL;
1280
std::string abort_msg;
1283
cwidget::threads::mutex m;
1284
cwidget::threads::condition c;
1287
boost::shared_ptr<background_continuation> k;
1288
k.reset(new solution_return_continuation(sol, abort_msg,
1290
get_solution_background(solution_num, max_steps, k,
1291
&inline_continuation_trampoline);
1295
cwidget::threads::mutex::lock cond_l(m);
1297
while(!sol && !oot && !oos)
1303
throw NoMoreSolutions();
1304
else if(sol == NULL)
1305
throw SolutionSearchAbortException(abort_msg);
1310
bool resolver_manager::get_is_keep_all_solution(unsigned int solution_num,
1313
cwidget::threads::mutex::lock l(mutex);
1315
get_solution(solution_num, max_steps);
1318
cwidget::threads::mutex::lock l2(solutions_mutex);
1319
eassert(solution_num < solutions.size());
1321
return solutions[solution_num]->get_is_keep_all_solution();;
1325
void resolver_manager::get_solution_background(unsigned int solution_num,
1327
const boost::shared_ptr<background_continuation> &k,
1328
post_thunk_f post_thunk)
1330
cwidget::threads::mutex::lock l(mutex);
1332
// It's necessary to stop the background thread because we might be
1333
// decreasing the maximum number of steps to search.
1334
background_suspender bs(*this);
1336
eassert(resolver_exists());
1338
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1339
if(solution_num < solutions.size())
1341
const generic_solution<aptitude_universe> *sol = solutions[solution_num]->get_solution();
1350
cwidget::threads::mutex::lock control_lock(background_control_mutex);
1351
pending_jobs.push(job_request(solution_num, max_steps, k, post_thunk));
1352
background_control_cond.wake_all();
1355
class blocking_continuation : public resolver_manager::background_continuation
1357
/** The real continuation */
1358
boost::shared_ptr<resolver_manager::background_continuation> k;
1360
/** The solution for which we are searching. */
1361
unsigned int solution_num;
1363
/** The channel through which the result should be announced. */
1364
cwidget::threads::box<bool> &result_box;
1366
/** The number of steps to try searching for a solution after this if
1369
int remaining_steps;
1371
/** The manager associated with this continuation. */
1372
resolver_manager &m;
1374
/** \brief How to invoke thunks safely. */
1375
post_thunk_f post_thunk;
1378
blocking_continuation(const boost::shared_ptr<background_continuation> &_k,
1379
unsigned int _solution_num,
1380
cwidget::threads::box<bool> &_result_box,
1381
int _remaining_steps,
1382
resolver_manager &_m,
1383
post_thunk_f _post_thunk)
1384
: k(_k), solution_num(_solution_num), result_box(_result_box),
1385
remaining_steps(_remaining_steps), m(_m),
1386
post_thunk(_post_thunk)
1390
void success(const generic_solution<aptitude_universe> &sol)
1392
sigc::slot<void> success_slot =
1393
sigc::bind(sigc::mem_fun(*k,
1394
&background_continuation::success),
1397
post_thunk(make_keepalive_slot(success_slot, k));
1398
result_box.put(true);
1401
void no_more_solutions()
1403
sigc::slot<void> no_more_solutions_slot =
1404
sigc::mem_fun(*k, &background_continuation::no_more_solutions);
1406
post_thunk(make_keepalive_slot(no_more_solutions_slot, k));
1407
result_box.put(true);
1412
m.get_solution_background(solution_num, remaining_steps, k, post_thunk);
1414
result_box.put(false);
1419
// Give up and run in the background.
1420
m.get_solution_background(solution_num, remaining_steps, k, post_thunk);
1422
result_box.put(false);
1425
void aborted(const std::string &errmsg)
1427
sigc::slot<void> aborted_slot =
1428
sigc::bind(sigc::mem_fun(*k, &background_continuation::aborted),
1431
post_thunk(make_keepalive_slot(aborted_slot, k));
1432
result_box.put(true);
1436
template<typename T>
1437
void resolver_manager::resolver_manipulation(const T &t,
1438
void (generic_problem_resolver<aptitude_universe>::*action)(const T &, undo_group *),
1439
const resolver_interaction &act)
1441
cwidget::threads::mutex::lock l(mutex);
1442
background_suspender bs(*this);
1444
undo_group *undo = new undo_group;
1445
(resolver->*action)(t, undo);
1449
undos->add_item(undo);
1451
actions_since_last_solution.push_back(act);
1458
void resolver_manager::reject_break_holds()
1460
cwidget::threads::mutex::lock l(mutex);
1461
background_suspender bs(*this);
1463
std::auto_ptr<undo_group> undo(new undo_group);
1465
for(aptitude_universe::package_iterator pi = resolver->get_universe().packages_begin();
1468
const aptitude_universe::package p = *pi;
1470
for(aptitude_universe::package::version_iterator vi = p.versions_begin(); !vi.end(); ++vi)
1472
const aptitude_universe::version v = *vi;
1473
if(resolver->is_break_hold(v))
1475
actions_since_last_solution.push_back(resolver_interaction::RejectVersion(v));
1482
undos->add_item(undo.release());
1489
void resolver_manager::reject_version(const aptitude_resolver_version &ver)
1491
resolver_manipulation(ver, &aptitude_resolver::reject_version,
1492
resolver_interaction::RejectVersion(ver));
1493
version_accept_reject_changed(ver);
1496
void resolver_manager::unreject_version(const aptitude_resolver_version &ver)
1498
resolver_manipulation(ver, &aptitude_resolver::unreject_version,
1499
resolver_interaction::UnRejectVersion(ver));
1500
version_accept_reject_changed(ver);
1503
bool resolver_manager::is_rejected(const aptitude_resolver_version &ver)
1505
cwidget::threads::mutex::lock l(mutex);
1508
return resolver->is_rejected(ver);
1511
void resolver_manager::mandate_version(const aptitude_resolver_version &ver)
1513
resolver_manipulation(ver, &aptitude_resolver::mandate_version,
1514
resolver_interaction::MandateVersion(ver));
1515
version_accept_reject_changed(ver);
1518
void resolver_manager::unmandate_version(const aptitude_resolver_version &ver)
1520
resolver_manipulation(ver, &aptitude_resolver::unmandate_version,
1521
resolver_interaction::UnMandateVersion(ver));
1522
version_accept_reject_changed(ver);
1525
bool resolver_manager::is_mandatory(const aptitude_resolver_version &ver)
1527
cwidget::threads::mutex::lock l(mutex);
1530
return resolver->is_mandatory(ver);
1533
void resolver_manager::harden_dep(const aptitude_resolver_dep &dep)
1535
resolver_manipulation(dep, &aptitude_resolver::harden,
1536
resolver_interaction::HardenDep(dep));
1537
break_dep_accept_reject_changed(dep);
1540
void resolver_manager::unharden_dep(const aptitude_resolver_dep &dep)
1542
resolver_manipulation(dep, &aptitude_resolver::unharden,
1543
resolver_interaction::UnHardenDep(dep));
1544
break_dep_accept_reject_changed(dep);
1547
bool resolver_manager::is_hardened(const aptitude_resolver_dep &dep)
1549
cwidget::threads::mutex::lock l(mutex);
1552
return resolver->is_hardened(dep);
1555
void resolver_manager::approve_broken_dep(const aptitude_resolver_dep &dep)
1557
resolver_manipulation(dep, &aptitude_resolver::approve_break,
1558
resolver_interaction::ApproveBrokenDep(dep));
1559
break_dep_accept_reject_changed(dep);
1562
void resolver_manager::unapprove_broken_dep(const aptitude_resolver_dep &dep)
1564
resolver_manipulation(dep, &aptitude_resolver::unapprove_break,
1565
resolver_interaction::UnApproveBrokenDep(dep));
1566
break_dep_accept_reject_changed(dep);
1569
bool resolver_manager::is_approved_broken(const aptitude_resolver_dep &dep)
1571
cwidget::threads::mutex::lock l(mutex);
1572
eassert(resolver != NULL);
1574
return resolver->is_approved_broken(dep);
1577
bool resolver_manager::has_undo_items()
1579
cwidget::threads::mutex::lock l(mutex);
1581
return undos->size() > 0;
1584
bool resolver_manager::undo()
1586
cwidget::threads::mutex::lock l(mutex);
1588
if(undos->size() > 0)
1590
background_suspender bs(*this);
1594
actions_since_last_solution.push_back(resolver_interaction::Undo());
1607
void resolver_manager::select_solution(unsigned int solnum)
1609
cwidget::threads::mutex::lock l(mutex);
1611
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1612
if(solnum >= 0 && solnum <= solutions.size())
1613
selected_solution = solnum;
1620
void resolver_manager::discard_error_information()
1622
cwidget::threads::mutex::lock l(mutex);
1624
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1626
solution_search_aborted = false;
1627
solution_search_abort_msg.clear();
1635
void resolver_manager::select_next_solution()
1637
cwidget::threads::mutex::lock l(mutex);
1639
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1640
if(selected_solution < solutions.size())
1641
++selected_solution;
1648
void resolver_manager::select_previous_solution()
1650
cwidget::threads::mutex::lock l(mutex);
1652
cwidget::threads::mutex::lock sol_l(solutions_mutex);
1653
if(selected_solution > 0)
1654
--selected_solution;
1661
void resolver_manager::tweak_score(const pkgCache::PkgIterator &pkg,
1662
const pkgCache::VerIterator &ver,
1665
cwidget::threads::mutex::lock l(mutex);
1666
background_suspender bs(*this);
1668
eassert(resolver_exists());
1669
eassert(resolver->fresh());
1671
aptitude_resolver_version res_ver;
1673
res_ver = aptitude_resolver_version::make_removal(pkg, *cache_file);
1675
res_ver = aptitude_resolver_version::make_install(ver, *cache_file);
1677
resolver->add_version_score(res_ver, score);
1680
void resolver_manager::dump(ostream &out)
1682
cwidget::threads::mutex::lock l(mutex);
1683
background_suspender bs(*this);
1685
if(!resolver_exists())
1688
// First, dump the universe.
1689
dump_universe(resolver->get_universe(), out);
1691
// Now dump the scores as a test instruction.
1692
out << "TEST " << resolver->get_step_score() << " "
1693
<< resolver->get_broken_score() << " "
1694
<< resolver->get_unresolved_soft_dep_score() << " "
1695
<< resolver->get_infinity() << " "
1696
<< resolver->get_full_solution_score() << " ";
1698
resolver->dump_scores(out);
1700
out << "EXPECT ( " << aptcfg->FindI(PACKAGE "::ProblemResolver::StepLimit", defaultStepLimit) << " ANY )" << std::endl;
1703
void resolver_manager::maybe_start_solution_calculation(const boost::shared_ptr<background_continuation> &k,
1704
post_thunk_f post_thunk)
1706
state st = state_snapshot();
1708
if(st.resolver_exists &&
1709
st.selected_solution == st.generated_solutions &&
1710
!st.solutions_exhausted &&
1711
!st.background_thread_active &&
1712
!st.background_thread_aborted)
1714
const int selected = st.selected_solution;
1715
// TODO: duplication of information! These config values should
1716
// be moved into a central function that everyone else can call.
1717
const int limit = aptcfg->FindI(PACKAGE "::ProblemResolver::StepLimit", defaultStepLimit);
1720
get_solution_background(selected, limit, k, post_thunk);
1724
// Safe resolver logic:
1726
class resolver_manager::safe_resolver_continuation : public resolver_manager::background_continuation
1728
boost::shared_ptr<background_continuation> real_continuation;
1729
resolver_manager *manager;
1730
// Used to update the statistics in the manager.
1731
generic_solution<aptitude_universe> last_sol;
1732
post_thunk_f post_thunk;
1734
safe_resolver_continuation(const boost::shared_ptr<background_continuation> &_real_continuation,
1735
resolver_manager *_manager,
1736
const generic_solution<aptitude_universe> &_last_sol,
1737
post_thunk_f _post_thunk)
1738
: real_continuation(_real_continuation),
1740
last_sol(_last_sol),
1741
post_thunk(_post_thunk)
1746
safe_resolver_continuation(const boost::shared_ptr<background_continuation> &_real_continuation,
1747
resolver_manager *_manager,
1748
post_thunk_f _post_thunk)
1749
: real_continuation(_real_continuation),
1751
post_thunk(_post_thunk)
1755
void success(const generic_solution<aptitude_universe> &sol)
1757
logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
1759
LOG_TRACE(logger, "safe_resolve_deps: got intermediate solution: " << sol);
1761
typedef generic_choice<aptitude_universe> choice;
1762
typedef generic_choice_set<aptitude_universe> choice_set;
1764
// If the solution changed (i.e., we managed to find some new
1765
// upgrades), we should try again; otherwise we've found the
1766
// solution that we'll return to the user.
1767
if(!(last_sol.valid() &&
1768
sol.get_choices() == last_sol.get_choices()))
1770
// The solution changed; prepare the resolver for the next
1774
// Mandate all the upgrades and installs in this solution,
1775
// then ask for the next solution. The goal is to try to
1776
// find the best solution, not just some solution, but to
1777
// preserve our previous decisions in order to avoid
1778
// thrashing around between alternatives.
1779
for(choice_set::const_iterator it = sol.get_choices().begin();
1780
it != sol.get_choices().end(); ++it)
1782
switch(it->get_type())
1784
case choice::install_version:
1786
const pkgCache::PkgIterator p(it->get_ver().get_pkg());
1788
if(it->get_ver().get_ver() != p.CurrentVer())
1791
"safe_resolve_deps: Mandating the upgrade or install " << it->get_ver()
1792
<< ", since it was produced as part of a solution.");
1793
manager->mandate_version(it->get_ver());
1798
"safe_resolve_deps: Not mandating " << it->get_ver()
1799
<< ", since it is a hold.");
1806
// Nothing to do otherwise.
1812
// NULL out the sub-continuation so that we don't accidentally
1813
// trigger it twice.
1814
boost::shared_ptr<background_continuation> k = real_continuation;
1815
real_continuation.reset();
1818
boost::shared_ptr<safe_resolver_continuation> safe_resolver_k;
1819
safe_resolver_k.reset(new safe_resolver_continuation(k, manager, sol, post_thunk));
1821
// Hold the global lock on the solution so that we can
1822
// guarantee that we're calculating the next solution.
1823
// (otherwise there's a potential race between
1824
// generated_solutions_count() and get_solution_background())
1825
cwidget::threads::mutex::lock l(manager->mutex);
1827
const int limit = aptcfg->FindI(PACKAGE "::ProblemResolver::StepLimit", defaultStepLimit);
1829
manager->get_solution_background(manager->generated_solution_count(),
1830
limit, safe_resolver_k, post_thunk);
1834
// Internal error that should never happen, but try to survive
1837
"safe_resolve_deps: Internal error: the resolver unexpectedly produced the same result twice: " << last_sol << " = " << sol);
1839
// Note: no need to use post_thunk, since we've already passed
1840
// through it to get here.
1841
if(real_continuation.get() != NULL)
1842
real_continuation->success(sol);
1844
LOG_WARN(logger, "safe_resolve_deps: should send the end solution to the real continuation, but it's NULL.");
1848
void no_more_solutions()
1850
logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
1852
if(last_sol.valid())
1854
LOG_TRACE(logger, "safe_resolve_deps: no more solutions; returning the last seen solution.");
1856
if(real_continuation.get() != NULL)
1857
real_continuation->success(last_sol);
1859
LOG_WARN(logger, "safe_resolve_deps: should return the last seen solution, but the continuation is NULL.");
1863
LOG_TRACE(logger, "safe_resolve_deps: unable to find any solutions.");
1865
if(real_continuation.get() != NULL)
1866
real_continuation->no_more_solutions();
1868
LOG_WARN(logger, "safe_resolve_deps: should report that there are no solutions, but the continuation is NULL.");
1874
logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
1876
if(last_sol.valid())
1878
LOG_TRACE(logger, "safe_resolve_deps: ran out of time searching for a solution; returning the last one that was computed.");
1880
if(real_continuation.get() != NULL)
1881
real_continuation->success(last_sol);
1883
LOG_WARN(logger, "safe_resolve_deps: should return the last seen solution, but the continuation is NULL.");
1887
LOG_TRACE(logger, "safe_resolve_deps: ran out of time before finding any solutions.");
1889
if(real_continuation.get() != NULL)
1890
real_continuation->no_more_time();
1892
LOG_WARN(logger, "safe_resolve_deps: should report that we ran out of time, but the continuation is NULL.");
1898
logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
1900
// Should never happen. In fact, no code calls interrupted() --
1901
// is that a vestigial function?
1902
LOG_WARN(logger, "safe_resolve_deps: someone interrupted the solution search!");
1905
void aborted(const std::string &errmsg)
1907
logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
1909
// Should we try to return the current solution if there is one?
1910
LOG_FATAL(logger, "safe_resolve_deps: aborted by exception: " << errmsg);
1911
if(real_continuation.get() != NULL)
1912
real_continuation->aborted(errmsg);
1914
LOG_WARN(logger, "safe_resolve_deps: should report that we were interrupted by an exception, but the continuation is NULL. Exception: " << errmsg);
1918
void resolver_manager::setup_safe_resolver(bool no_new_installs, bool no_new_upgrades)
1920
eassert(resolver_exists());
1922
logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolverSetup());
1925
"setup_safe_resolver: Setting up the resolver state for safe dependency resolution.");
1929
background_suspender bs(*this);
1931
for(pkgCache::PkgIterator p = (*cache_file)->PkgBegin();
1934
// Forbid the resolver from removing installed packages.
1935
if(!p.CurrentVer().end())
1937
aptitude_resolver_version remove_p =
1938
aptitude_resolver_version::make_removal(p,
1942
"setup_safe_resolver: Rejecting the removal of the package " << remove_p.get_package() << ".");
1944
reject_version(remove_p);
1947
// Look up the version that's to-be-installed according to the
1948
// resolver's initial state.
1949
aptitude_resolver_package aptitude_p(p, *cache_file);
1950
aptitude_resolver_version p_initial_version =
1951
resolver->get_initial_state().version_of(aptitude_p);
1953
// Forbid all real versions that aren't the current version or
1954
// the candidate version.
1955
for(pkgCache::VerIterator v = p.VersionList();
1958
// For our purposes, all half-unpacked etc states are
1960
const bool p_is_installed =
1961
p->CurrentState != pkgCache::State::NotInstalled &&
1962
p->CurrentState != pkgCache::State::ConfigFiles;
1964
bool p_will_install;
1965
if(!p_initial_version.get_ver().end())
1967
if(p->CurrentState == pkgCache::State::NotInstalled ||
1968
p->CurrentState == pkgCache::State::ConfigFiles)
1969
p_will_install = true;
1971
p_will_install = (p.CurrentVer() != p_initial_version.get_ver());
1974
p_will_install = false;
1976
const bool v_is_a_new_install = !p_is_installed && !p_will_install;
1977
const bool v_is_a_new_upgrade = p_is_installed && p_will_install;
1978
const bool v_is_a_non_default_version = v != (*cache_file)[p].CandidateVerIter(*cache_file);
1980
if(v != p.CurrentVer() &&
1981
// Disallow installing not-installed packages that
1982
// aren't marked for installation if
1983
// no_new_installs is set.
1984
((v_is_a_new_install && no_new_installs) ||
1985
(v_is_a_new_upgrade && no_new_upgrades) ||
1986
v_is_a_non_default_version))
1988
aptitude_resolver_version p_v =
1989
aptitude_resolver_version::make_install(v, *cache_file);
1991
if(logger->isEnabledFor(logging::DEBUG_LEVEL))
1993
if(v_is_a_non_default_version)
1994
LOG_DEBUG(logger, "setup_safe_resolver: Rejecting " << p_v << " (it is a non-default version).");
1995
else if(v_is_a_new_install)
1996
LOG_DEBUG(logger, "setup_safe_resolver: Rejecting " << p_v << " (it is a new install).");
1997
else // if(v_is_a_new_upgrade)
1998
LOG_DEBUG(logger, "setup_safe_resolver: Rejecting " << p_v << " (it is a new upgrade).");
2001
reject_version(p_v);
2007
void resolver_manager::safe_resolve_deps_background(bool no_new_installs, bool no_new_upgrades,
2008
const boost::shared_ptr<background_continuation> &k,
2009
post_thunk_f post_thunk)
2011
setup_safe_resolver(no_new_installs, no_new_upgrades);
2012
maybe_start_solution_calculation(boost::make_shared<safe_resolver_continuation>(k, this, post_thunk),