~ubuntu-branches/ubuntu/raring/aptitude/raring

« back to all changes in this revision

Viewing changes to .pc/gcc-4.8/src/generic/apt/resolver_manager.cc

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-02-26 09:14:45 UTC
  • Revision ID: package-import@ubuntu.com-20130226091445-lju4uwlytxt9zahe
Tags: 0.6.8.1-2ubuntu2
Fix build failure with GCC 4.8.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// resolver_manager.cc
 
2
//
 
3
//   Copyright (C) 2005, 2007-2010 Daniel Burrows
 
4
//
 
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.
 
9
//
 
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.
 
14
//
 
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.
 
19
 
 
20
#include "resolver_manager.h"
 
21
 
 
22
#include <aptitude.h>
 
23
#include "apt.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"
 
30
 
 
31
#include <boost/format.hpp>
 
32
#include <boost/make_shared.hpp>
 
33
 
 
34
#include <loggers.h>
 
35
 
 
36
#include <generic/problemresolver/problemresolver.h>
 
37
#include <generic/util/temp.h>
 
38
#include <generic/util/undo.h>
 
39
 
 
40
#include <apt-pkg/error.h>
 
41
#include <apt-pkg/strutl.h>
 
42
 
 
43
#include <sigc++/bind.h>
 
44
#include <sigc++/functors/mem_fun.h>
 
45
 
 
46
#include <fstream>
 
47
 
 
48
#include <sys/types.h>
 
49
#include <sys/wait.h>
 
50
 
 
51
using aptitude::Loggers;
 
52
 
 
53
const int defaultStepLimit = 500000;
 
54
 
 
55
class resolver_manager::resolver_interaction
 
56
{
 
57
public:
 
58
  /** \brief The type tag of a resolver interaction. */
 
59
  enum tag
 
60
    {
 
61
      reject_version,
 
62
      unreject_version,
 
63
      mandate_version,
 
64
      unmandate_version,
 
65
      harden_dep,
 
66
      unharden_dep,
 
67
      approve_broken_dep,
 
68
      unapprove_broken_dep,
 
69
      undo
 
70
    };
 
71
 
 
72
private:
 
73
  tag type;
 
74
 
 
75
  aptitude_resolver_version version;
 
76
  aptitude_resolver_dep dep;
 
77
 
 
78
  resolver_interaction(tag _type,
 
79
                       const aptitude_resolver_version &_version,
 
80
                       const aptitude_resolver_dep &_dep)
 
81
    : type(_type), version(_version), dep(_dep)
 
82
  {
 
83
  }
 
84
 
 
85
public:
 
86
  static resolver_interaction RejectVersion(const aptitude_resolver_version &version)
 
87
  {
 
88
    return resolver_interaction(reject_version, version,
 
89
                                aptitude_resolver_dep());
 
90
  }
 
91
 
 
92
  static resolver_interaction UnRejectVersion(const aptitude_resolver_version &version)
 
93
  {
 
94
    return resolver_interaction(unreject_version, version,
 
95
                                aptitude_resolver_dep());
 
96
  }
 
97
 
 
98
  static resolver_interaction MandateVersion(const aptitude_resolver_version &version)
 
99
  {
 
100
    return resolver_interaction(mandate_version, version,
 
101
                                aptitude_resolver_dep());
 
102
  }
 
103
 
 
104
  static resolver_interaction UnMandateVersion(const aptitude_resolver_version &version)
 
105
  {
 
106
    return resolver_interaction(unmandate_version, version,
 
107
                                aptitude_resolver_dep());
 
108
  }
 
109
 
 
110
  static resolver_interaction HardenDep(const aptitude_resolver_dep &dep)
 
111
  {
 
112
    return resolver_interaction(harden_dep,
 
113
                                aptitude_resolver_version(),
 
114
                                dep);
 
115
  }
 
116
 
 
117
  static resolver_interaction UnHardenDep(const aptitude_resolver_dep &dep)
 
118
  {
 
119
    return resolver_interaction(unharden_dep,
 
120
                                aptitude_resolver_version(),
 
121
                                dep);
 
122
  }
 
123
 
 
124
  static resolver_interaction ApproveBrokenDep(const aptitude_resolver_dep &dep)
 
125
  {
 
126
    return resolver_interaction(approve_broken_dep,
 
127
                                aptitude_resolver_version(),
 
128
                                dep);
 
129
  }
 
130
 
 
131
  static resolver_interaction UnApproveBrokenDep(const aptitude_resolver_dep &dep)
 
132
  {
 
133
    return resolver_interaction(unapprove_broken_dep,
 
134
                                aptitude_resolver_version(),
 
135
                                dep);
 
136
  }
 
137
 
 
138
  static resolver_interaction Undo()
 
139
  {
 
140
    return resolver_interaction(undo,
 
141
                                aptitude_resolver_version(),
 
142
                                aptitude_resolver_dep());
 
143
  }
 
144
 
 
145
  tag get_type() const { return type; }
 
146
  const aptitude_resolver_version &get_version() const
 
147
  {
 
148
    eassert(!version.get_pkg().end());
 
149
    return version;
 
150
  }
 
151
  const aptitude_resolver_dep &get_dep() const
 
152
  {
 
153
    eassert(!dep.get_dep().end());
 
154
    return dep;
 
155
  }
 
156
};
 
157
 
 
158
resolver_manager::solution_information::~solution_information()
 
159
{
 
160
  delete interactions;
 
161
  delete solution;
 
162
}
 
163
 
 
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
 
168
// be a bottleneck.
 
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),
 
172
   resolver(NULL),
 
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),
 
179
   resolver_null(true),
 
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))
 
185
{
 
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));
 
188
 
 
189
  aptcfg->connect("Apt::Install-Recommends",
 
190
                  sigc::mem_fun(this,
 
191
                                &resolver_manager::discard_resolver));
 
192
 
 
193
  start_background_thread();
 
194
 
 
195
  maybe_create_resolver();
 
196
}
 
197
 
 
198
resolver_manager::~resolver_manager()
 
199
{
 
200
  eassert(background_thread_running);
 
201
 
 
202
  discard_resolver();
 
203
 
 
204
  kill_background_thread();
 
205
 
 
206
  for(std::vector<const solution_information *>::const_iterator it =
 
207
        solutions.begin(); it != solutions.end(); ++it)
 
208
    {
 
209
      delete *it;
 
210
    }
 
211
 
 
212
  delete undos;
 
213
}
 
214
 
 
215
void resolver_manager::reset_resolver()
 
216
{
 
217
  discard_resolver();
 
218
  maybe_create_resolver();
 
219
}
 
220
 
 
221
resolver_manager::background_continuation::~background_continuation()
 
222
{
 
223
}
 
224
 
 
225
class resolver_manager::background_suspender
 
226
{
 
227
  resolver_manager &m;
 
228
 
 
229
  bool suspended;
 
230
public:
 
231
  background_suspender(resolver_manager &_m)
 
232
    :m(_m), suspended(true)
 
233
  {
 
234
    m.suspend_background_thread();
 
235
  }
 
236
 
 
237
  void unsuspend()
 
238
  {
 
239
    if(suspended)
 
240
      {
 
241
        m.unsuspend_background_thread();
 
242
        suspended = false;
 
243
      }
 
244
  }
 
245
 
 
246
  ~background_suspender()
 
247
  {
 
248
    if(suspended)
 
249
      m.unsuspend_background_thread();
 
250
  }
 
251
};
 
252
 
 
253
/** A class that assigns a value to an object when it is destroyed.
 
254
 */
 
255
template<typename T>
 
256
class set_when_destroyed
 
257
{
 
258
  T &target;
 
259
  T val;
 
260
 
 
261
public:
 
262
  /** Create a set_when_destroyed.
 
263
   *
 
264
   *  \param _target The object to be set.
 
265
   *  \param _val The value to assign to _target.
 
266
   */
 
267
  set_when_destroyed(T &_target, const T &_val)
 
268
    : target(_target), val(_val)
 
269
  {
 
270
  }
 
271
 
 
272
  /** Assign val to target. */
 
273
  ~set_when_destroyed()
 
274
  {
 
275
    target = val;
 
276
  }
 
277
};
 
278
 
 
279
void resolver_manager::write_test_control_file(const std::string &outDir,
 
280
                                               const std::set<aptitude_resolver_package> &visited_packages,
 
281
                                               int solution_number)
 
282
{
 
283
  static const char * const strBadChars = "\\\"";
 
284
 
 
285
  std::string control_filename = outDir + "/APTITUDE.TRACE";
 
286
  std::ofstream control_file(control_filename.c_str());
 
287
  if(!control_file)
 
288
    return; // Should we output an error here?
 
289
 
 
290
  // The state files are written out in make_truncated_state_copy.
 
291
  // Here we just indicate the actual installs / removals that are
 
292
  // queued up.
 
293
 
 
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();
 
298
      ++it)
 
299
    {
 
300
      const aptitude_resolver_package &p(*it);
 
301
      if(visited_packages.find(p) == visited_packages.end())
 
302
        continue;
 
303
 
 
304
      pkg_action_state action = find_pkg_state(p.get_pkg(), **cache_file);
 
305
      std::string actionstr;
 
306
      switch(action)
 
307
        {
 
308
        case pkg_unused_remove:
 
309
        case pkg_auto_remove:
 
310
        case pkg_remove:
 
311
          actionstr = "remove";
 
312
          break;
 
313
 
 
314
        case pkg_auto_install:
 
315
        case pkg_downgrade:
 
316
        case pkg_install:
 
317
        case pkg_upgrade:
 
318
          actionstr = std::string("install ") +
 
319
            (*cache_file)[p.get_pkg()].InstVerIter(*cache_file).VerStr();
 
320
          break;
 
321
 
 
322
        default:
 
323
          break;
 
324
        }
 
325
 
 
326
      if(!actionstr.empty())
 
327
        control_file << "  " << actionstr << " \"" << QuoteString(p.get_name(), strBadChars) << "\"" << std::endl;;
 
328
    }
 
329
 
 
330
  control_file << "}" << std::endl;
 
331
  control_file << std::endl;
 
332
 
 
333
  {
 
334
    cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
335
 
 
336
    for(std::vector<const solution_information *>::const_iterator infIt =
 
337
          solutions.begin();
 
338
        infIt != solutions.end() && infIt - solutions.begin() <= solution_number;
 
339
        ++infIt)
 
340
      {
 
341
        control_file << "test {" << std::endl;
 
342
 
 
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();
 
347
 
 
348
        for(std::vector<resolver_interaction>::const_iterator actIt =
 
349
              acts.begin(); actIt != acts.end(); ++actIt)
 
350
          {
 
351
            switch(actIt->get_type())
 
352
              {
 
353
              case resolver_interaction::reject_version:
 
354
                control_file << "reject " << actIt->get_version() << std::endl;
 
355
                break;
 
356
              case resolver_interaction::unreject_version:
 
357
                control_file << "unreject " << actIt->get_version() << std::endl;
 
358
                break;
 
359
              case resolver_interaction::mandate_version:
 
360
                control_file << "mandate " << actIt->get_version() << std::endl;
 
361
                break;
 
362
              case resolver_interaction::unmandate_version:
 
363
                control_file << "unmandate " << actIt->get_version() << std::endl;
 
364
                break;
 
365
              case resolver_interaction::harden_dep:
 
366
                control_file << "harden " << actIt->get_dep() << std::endl;
 
367
                break;
 
368
              case resolver_interaction::unharden_dep:
 
369
                control_file << "unharden " << actIt->get_dep() << std::endl;
 
370
                break;
 
371
              case resolver_interaction::approve_broken_dep:
 
372
                control_file << "approve_broken " << actIt->get_dep() << std::endl;
 
373
                break;
 
374
              case resolver_interaction::unapprove_broken_dep:
 
375
                control_file << "unapprove_broken " << actIt->get_dep() << std::endl;
 
376
                break;
 
377
              case resolver_interaction::undo:
 
378
                control_file << "undo" << std::endl;
 
379
                break;
 
380
              }
 
381
          }
 
382
 
 
383
        control_file << "  expect " << inf.get_ticks() << " {" << std::endl;
 
384
 
 
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)
 
393
          {
 
394
            switch(solChoiceIt->get_type())
 
395
              {
 
396
              case choice::install_version:
 
397
                control_file << "    install \""
 
398
                             << QuoteString(solChoiceIt->get_ver().get_package().get_name(), strBadChars)
 
399
                             << "\" \""
 
400
                             << QuoteString(solChoiceIt->get_ver().get_name(), strBadChars)
 
401
                             << "\""
 
402
                             << std::endl;
 
403
                break;
 
404
 
 
405
              case choice::break_soft_dep:
 
406
                {
 
407
                  dep d(solChoiceIt->get_dep());
 
408
                  version source(d.get_source());
 
409
 
 
410
                  control_file << "    break \""
 
411
                               << QuoteString(source.get_package().get_name(), strBadChars)
 
412
                               << "\" \""
 
413
                               << QuoteString(source.get_name(), strBadChars)
 
414
                               << "\" -> {";
 
415
 
 
416
                  bool first = true;
 
417
                  for(dep::solver_iterator sIt = d.solvers_begin();
 
418
                      !sIt.end(); ++sIt)
 
419
                    {
 
420
                      if(first)
 
421
                        first = false;
 
422
                      else
 
423
                        control_file << ", ";
 
424
 
 
425
                      version solver(*sIt);
 
426
                      control_file << "\""
 
427
                                   << QuoteString(solver.get_package().get_name(), strBadChars)
 
428
                                   << "\" \""
 
429
                                   << QuoteString(solver.get_name(), strBadChars)
 
430
                                   << "\"";
 
431
                    }
 
432
 
 
433
                  control_file << "}" << std::endl;
 
434
                }
 
435
 
 
436
                break;
 
437
 
 
438
              default:
 
439
                // ... recover sanely.
 
440
                control_file << "ERROR" << std::endl;
 
441
              }
 
442
          }
 
443
        control_file << "  }" << std::endl;
 
444
 
 
445
        control_file << "}" << std::endl;
 
446
      }
 
447
  }
 
448
}
 
449
 
 
450
void resolver_manager::dump_visited_packages(const std::set<aptitude_resolver_package> &visited_packages,
 
451
                                             int solution_number)
 
452
{
 
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())
 
458
    {
 
459
      temp_trace_dir = temp::dir("aptitude-trace-dump");
 
460
      trace_dir = temp_trace_dir.get_name();
 
461
    }
 
462
  else
 
463
    return;
 
464
 
 
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)
 
468
    {
 
469
      packages.insert((*it).get_pkg());
 
470
    }
 
471
 
 
472
  aptitude::apt::make_truncated_state_copy(trace_dir, packages);
 
473
  write_test_control_file(trace_dir, visited_packages, solution_number);
 
474
 
 
475
  if(!resolver_trace_file.empty())
 
476
    {
 
477
      int pid = fork();
 
478
      if(pid == -1)
 
479
        _error->Errno("fork", "Unable to run \"tar\" to create the trace file.");
 
480
      else if(pid != 0)
 
481
        {
 
482
          int status;
 
483
          while(waitpid(pid, &status, 0) != pid ||
 
484
                (!WIFEXITED(status) &&
 
485
                 !WIFSIGNALED(status)))
 
486
            ;
 
487
 
 
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));
 
492
 
 
493
          // Whee, we win!
 
494
        }
 
495
      else
 
496
        {
 
497
          // Should I close open fds here?
 
498
 
 
499
          // Should I allow tar to be found on the path?
 
500
          execl("/bin/tar", "/bin/tar", "czf",
 
501
                resolver_trace_file.c_str(),
 
502
                "-C",
 
503
                trace_dir.c_str(),
 
504
                ".",
 
505
                NULL);
 
506
 
 
507
          // TODO: communicate to the parent that we couldn't find
 
508
          // tar?
 
509
          exit(1);
 
510
        }
 
511
    }
 
512
}
 
513
 
 
514
namespace
 
515
{
 
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)
 
519
  {
 
520
    f();
 
521
  }
 
522
}
 
523
 
 
524
// This assumes that background_resolver_active is empty when it
 
525
// starts (see restart_background_resolver)
 
526
//
 
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
 
529
// interactively)
 
530
void resolver_manager::background_thread_execution()
 
531
{
 
532
  logging::LoggerPtr logger = Loggers::getAptitudeResolverThread();
 
533
  LOG_TRACE(logger, "Resolver thread: starting.");
 
534
  std::set<aptitude_resolver_package> visited_packages;
 
535
 
 
536
  cwidget::threads::mutex::lock l(background_control_mutex);
 
537
  set_when_destroyed<bool> cancel_set_running(background_thread_running, false);
 
538
 
 
539
  while(1)
 
540
    {
 
541
      while((background_thread_suspend_count > 0 || resolver_null || pending_jobs.empty()) &&
 
542
            !background_thread_killed)
 
543
        {
 
544
          if(logger->isEnabledFor(logging::TRACE_LEVEL))
 
545
            {
 
546
              std::vector<std::string> why_suspended;
 
547
              if(background_thread_suspend_count > 0)
 
548
                why_suspended.push_back("waiting to be unsuspended");
 
549
              if(resolver_null)
 
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");
 
553
 
 
554
              if(!why_suspended.empty())
 
555
                {
 
556
                  std::string msg;
 
557
                  for(std::vector<std::string>::const_iterator it = why_suspended.begin();
 
558
                      it != why_suspended.end(); ++it)
 
559
                    {
 
560
                      if(!msg.empty())
 
561
                        msg += ", ";
 
562
                      msg += *it;
 
563
                    }
 
564
 
 
565
                  LOG_TRACE(logger, "Resolver thread: " << msg << ".");
 
566
                }
 
567
            }
 
568
 
 
569
          background_control_cond.wait(l);
 
570
        }
 
571
 
 
572
      if(background_thread_killed)
 
573
        {
 
574
          LOG_TRACE(logger, "Resolver thread: exiting (killed).");
 
575
          break;
 
576
        }
 
577
 
 
578
      job_request job = pending_jobs.top();
 
579
      pending_jobs.pop();
 
580
 
 
581
      LOG_DEBUG(logger,
 
582
                "Resolver thread: got a new job { solution number = "
 
583
                << job.sol_num << ", max steps = " << job.max_steps
 
584
                << ", continuation = " << job.k << " }");
 
585
 
 
586
      background_thread_in_resolver = true;
 
587
      background_resolver_cond.wake_all();
 
588
      l.release();
 
589
 
 
590
      try
 
591
        {
 
592
          const aptitude_resolver::solution *sol =
 
593
            do_get_solution(job.max_steps,
 
594
                            job.sol_num,
 
595
                            visited_packages);
 
596
 
 
597
          LOG_DEBUG(logger,
 
598
                    "Resolver thread: got a solution: " << *sol);
 
599
 
 
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.
 
604
          l.acquire();
 
605
          dump_visited_packages(visited_packages,
 
606
                                job.sol_num);
 
607
          background_thread_in_resolver = false;
 
608
          background_resolver_cond.wake_all();
 
609
          l.release();
 
610
 
 
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),
 
615
                       *sol);
 
616
          // Wrap a keepalive slot around that so job.k lives.
 
617
          job.post_thunk(make_keepalive_slot(success_slot, job.k));
 
618
        }
 
619
      catch(InterruptedException)
 
620
        {
 
621
          // Put it back into the pot.
 
622
          l.acquire();
 
623
 
 
624
          LOG_DEBUG(logger,
 
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 << "}");
 
629
 
 
630
          dump_visited_packages(visited_packages,
 
631
                                job.sol_num);
 
632
          background_thread_in_resolver = false;
 
633
          background_resolver_cond.wake_all();
 
634
          pending_jobs.push(job);
 
635
 
 
636
          l.release();
 
637
        }
 
638
      catch(NoMoreSolutions)
 
639
        {
 
640
          l.acquire();
 
641
 
 
642
          LOG_DEBUG(logger,
 
643
                    "Resolver thread: out of solutions.");
 
644
 
 
645
          dump_visited_packages(visited_packages,
 
646
                                job.sol_num);
 
647
          background_thread_in_resolver = false;
 
648
          background_resolver_cond.wake_all();
 
649
          l.release();
 
650
 
 
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));
 
655
        }
 
656
      catch(NoMoreTime)
 
657
        {
 
658
          l.acquire();
 
659
 
 
660
          LOG_DEBUG(logger,
 
661
                    "Resolver thread: out of time.");
 
662
 
 
663
          dump_visited_packages(visited_packages,
 
664
                                job.sol_num);
 
665
          background_thread_in_resolver = false;
 
666
          background_resolver_cond.wake_all();
 
667
          l.release();
 
668
 
 
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));
 
673
        }
 
674
      catch(cwidget::util::Exception &e)
 
675
        {
 
676
          LOG_ERROR(logger,
 
677
                    "Resolver thread: caught a fatal error from the resolver: "
 
678
                    << e.errmsg());
 
679
 
 
680
          dump_visited_packages(visited_packages,
 
681
                                job.sol_num);
 
682
 
 
683
          sigc::slot<void> aborted_slot =
 
684
            sigc::bind(sigc::mem_fun(*job.k,
 
685
                                     &background_continuation::aborted),
 
686
                       e.errmsg());
 
687
          job.post_thunk(make_keepalive_slot(aborted_slot, job.k));
 
688
        }
 
689
 
 
690
      l.acquire();
 
691
 
 
692
      background_thread_in_resolver = false;
 
693
      background_resolver_cond.wake_all();
 
694
    }
 
695
}
 
696
 
 
697
// Need this because sigc slots aren't threadsafe :-(
 
698
struct resolver_manager::background_thread_bootstrap
 
699
{
 
700
  resolver_manager &m;
 
701
public:
 
702
  background_thread_bootstrap(resolver_manager &_m)
 
703
    :m(_m)
 
704
  {
 
705
  }
 
706
 
 
707
  void operator()()
 
708
  {
 
709
    m.background_thread_execution();
 
710
  }
 
711
};
 
712
 
 
713
void resolver_manager::start_background_thread()
 
714
{
 
715
  cwidget::threads::mutex::lock l(mutex);
 
716
 
 
717
  if(resolver_thread == NULL)
 
718
    {
 
719
      background_thread_running = true;
 
720
      resolver_thread = new cwidget::threads::thread(background_thread_bootstrap(*this));
 
721
    }
 
722
}
 
723
 
 
724
void resolver_manager::kill_background_thread()
 
725
{
 
726
  cwidget::threads::mutex::lock l(mutex);
 
727
 
 
728
  if(resolver_thread != NULL)
 
729
    {
 
730
      cwidget::threads::mutex::lock control_lock(background_control_mutex);
 
731
 
 
732
      if(resolver != NULL)
 
733
        resolver->cancel_solver();
 
734
      background_thread_killed = true;
 
735
      background_control_cond.wake_all();
 
736
 
 
737
      control_lock.release();
 
738
 
 
739
      resolver_thread->join();
 
740
      delete resolver_thread;
 
741
      resolver_thread = NULL;
 
742
 
 
743
 
 
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();
 
752
    }
 
753
}
 
754
 
 
755
void resolver_manager::suspend_background_thread()
 
756
{
 
757
  cwidget::threads::mutex::lock l(mutex);
 
758
 
 
759
  // May occur due to background_suspend objects existing while
 
760
  // kill_background_thread runs.
 
761
  if(resolver_thread == NULL)
 
762
    return;
 
763
 
 
764
  cwidget::threads::mutex::lock control_lock(background_control_mutex);
 
765
 
 
766
  if(resolver != NULL)
 
767
    resolver->cancel_solver();
 
768
 
 
769
  ++background_thread_suspend_count;
 
770
  background_control_cond.wake_all();
 
771
 
 
772
  while(background_thread_in_resolver)
 
773
    background_resolver_cond.wait(control_lock);
 
774
 
 
775
  if(resolver != NULL)
 
776
    resolver->uncancel_solver();
 
777
}
 
778
 
 
779
void resolver_manager::unsuspend_background_thread()
 
780
{
 
781
  cwidget::threads::mutex::lock l(mutex);
 
782
 
 
783
  if(resolver_thread == NULL)
 
784
    return;
 
785
 
 
786
  cwidget::threads::mutex::lock control_lock(background_control_mutex);
 
787
 
 
788
  eassert(background_thread_suspend_count > 0);
 
789
  --background_thread_suspend_count;
 
790
  background_control_cond.wake_all();
 
791
}
 
792
 
 
793
void resolver_manager::maybe_create_resolver()
 
794
{
 
795
  cwidget::threads::mutex::lock l(mutex);
 
796
 
 
797
  if(resolver == NULL && ((*cache_file)->BrokenCount() > 0 || !initial_installations.empty()))
 
798
    {
 
799
      {
 
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", "");
 
803
      }
 
804
      create_resolver();
 
805
 
 
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())
 
811
        discard_resolver();
 
812
    }
 
813
 
 
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
 
817
  // (maybe).
 
818
  l.release();
 
819
  state_changed();
 
820
}
 
821
 
 
822
void resolver_manager::discard_resolver()
 
823
{
 
824
  cwidget::threads::mutex::lock l(mutex);
 
825
 
 
826
  if(resolver == NULL)
 
827
    return;
 
828
 
 
829
  background_suspender bs(*this);
 
830
 
 
831
  undos->clear_items();
 
832
 
 
833
  delete resolver;
 
834
 
 
835
  {
 
836
    cwidget::threads::mutex::lock l2(solutions_mutex);
 
837
    actions_since_last_solution.clear();
 
838
    ticks_since_last_solution = 0;
 
839
 
 
840
    for(std::vector<const solution_information *>::const_iterator it =
 
841
          solutions.begin(); it != solutions.end(); ++it)
 
842
      delete *it;
 
843
 
 
844
    solutions.clear();
 
845
    solution_search_aborted = false;
 
846
    solution_search_abort_msg.clear();
 
847
    selected_solution = 0;
 
848
  }
 
849
 
 
850
  resolver = NULL;
 
851
 
 
852
  {
 
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();
 
857
  }
 
858
}
 
859
 
 
860
void resolver_manager::create_resolver()
 
861
{
 
862
  cwidget::threads::mutex::lock l(mutex);
 
863
  eassert(resolver == NULL);
 
864
 
 
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;
 
869
 
 
870
  const Configuration::Item * const root =
 
871
    aptcfg->Tree(PACKAGE "::ProblemResolver::Hints");
 
872
 
 
873
  if(root != NULL)
 
874
    {
 
875
      for(const Configuration::Item *itm = root->Child;
 
876
          itm != NULL; itm = itm -> Next)
 
877
        {
 
878
          aptitude_resolver::hint hint;
 
879
          if(aptitude_resolver::hint::parse(itm->Value, hint))
 
880
            hints.push_back(hint);
 
881
        }
 
882
    }
 
883
 
 
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!
 
897
 
 
898
 
 
899
  std::string cost_configuration = aptcfg->Find(PACKAGE "::ProblemResolver::SolutionCost",
 
900
                                                "safety,priority");
 
901
 
 
902
  boost::shared_ptr<std::vector<cost_component_structure> > cost_components;
 
903
  try
 
904
    {
 
905
      cost_components = parse_cost_settings(cost_configuration);
 
906
    }
 
907
  catch(ResolverCostParseException &ex)
 
908
    {
 
909
      LOG_ERROR(Loggers::getAptitudeResolver(),
 
910
                boost::format(_("Failed to parse the cost settings string: %s")) % ex.what());
 
911
 
 
912
      _error->Error(_("Failed to parse the cost settings string: %s"),
 
913
                    ex.what());
 
914
 
 
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> >();
 
918
 
 
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));
 
922
 
 
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));
 
926
    }
 
927
 
 
928
 
 
929
  aptitude_resolver_cost_settings cost_settings(cost_components);
 
930
 
 
931
 
 
932
  cost ignored_recommends_cost;
 
933
  {
 
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);
 
937
  }
 
938
 
 
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),
 
946
                                 cost_settings,
 
947
                                 initial_installations,
 
948
                                 (*cache_file),
 
949
                                 cache_file->Policy);
 
950
 
 
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
 
954
  // as manual.
 
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)
 
958
    {
 
959
      pkgCache::PkgIterator pkg(it->first.get_pkg());
 
960
      aptitude_resolver_package resolver_pkg(pkg, *cache_file);
 
961
 
 
962
      if(pkg->CurrentState != pkgCache::State::NotInstalled &&
 
963
         pkg->CurrentState != pkgCache::State::ConfigFiles)
 
964
        {
 
965
          manual_flags[resolver_pkg] =
 
966
            ((*cache_file)[pkg].Flags & pkgCache::Flag::Auto) == 0;
 
967
 
 
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.");
 
973
        }
 
974
      else
 
975
        {
 
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"));
 
981
        }
 
982
    }
 
983
 
 
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),
 
997
                              manual_flags,
 
998
                              hints);
 
999
 
 
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));
 
1005
 
 
1006
  {
 
1007
    cwidget::threads::mutex::lock l2(background_control_mutex);
 
1008
    resolver_null = false;
 
1009
    background_control_cond.wake_all();
 
1010
  }
 
1011
}
 
1012
 
 
1013
void resolver_manager::set_resolver_trace_dir(const std::string &path)
 
1014
{
 
1015
  cwidget::threads::mutex::lock l(background_control_mutex);
 
1016
  resolver_trace_dir = path;
 
1017
}
 
1018
 
 
1019
void resolver_manager::set_debug(bool activate)
 
1020
{
 
1021
  cwidget::threads::mutex::lock l(mutex);
 
1022
  background_suspender bs(*this);
 
1023
 
 
1024
  eassert(resolver_exists());
 
1025
 
 
1026
  resolver->set_debug(activate);
 
1027
}
 
1028
 
 
1029
bool resolver_manager::resolver_exists() const
 
1030
{
 
1031
  cwidget::threads::mutex::lock l(mutex);
 
1032
 
 
1033
  return resolver != NULL;
 
1034
}
 
1035
 
 
1036
unsigned int resolver_manager::generated_solution_count() const
 
1037
{
 
1038
  cwidget::threads::mutex::lock l(mutex);
 
1039
  cwidget::threads::mutex::lock l2(solutions_mutex);
 
1040
 
 
1041
  return solutions.size();
 
1042
}
 
1043
 
 
1044
bool resolver_manager::solution_generation_complete() // const
 
1045
{
 
1046
  return state_snapshot().solutions_exhausted;
 
1047
}
 
1048
 
 
1049
bool resolver_manager::solutions_at_start() const
 
1050
{
 
1051
  cwidget::threads::mutex::lock l(mutex);
 
1052
 
 
1053
  if(!resolver_exists())
 
1054
    return true;
 
1055
  else
 
1056
    return selected_solution == 0;
 
1057
}
 
1058
 
 
1059
bool resolver_manager::background_thread_active()
 
1060
{
 
1061
  cwidget::threads::mutex::lock l(mutex);
 
1062
 
 
1063
  cwidget::threads::mutex::lock ctl_l(background_control_mutex);
 
1064
 
 
1065
  return !pending_jobs.empty() || background_thread_in_resolver;
 
1066
}
 
1067
 
 
1068
bool resolver_manager::background_thread_aborted()
 
1069
{
 
1070
  cwidget::threads::mutex::lock l(mutex);
 
1071
 
 
1072
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1073
 
 
1074
  return solution_search_aborted;
 
1075
}
 
1076
 
 
1077
std::string resolver_manager::background_thread_abort_msg()
 
1078
{
 
1079
  cwidget::threads::mutex::lock l(mutex);
 
1080
 
 
1081
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1082
 
 
1083
  return solution_search_aborted ? solution_search_abort_msg : "";
 
1084
}
 
1085
 
 
1086
resolver_manager::state resolver_manager::state_snapshot()
 
1087
{
 
1088
  cwidget::threads::mutex::lock l(mutex);
 
1089
 
 
1090
  cwidget::threads::mutex::lock ctl_l(background_control_mutex);
 
1091
 
 
1092
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1093
 
 
1094
  state rval;
 
1095
 
 
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;
 
1104
 
 
1105
  if(resolver != NULL)
 
1106
    {
 
1107
      aptitude_resolver::queue_counts c = resolver->get_counts();
 
1108
 
 
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;
 
1114
    }
 
1115
  else
 
1116
    {
 
1117
      rval.open_size      = 0;
 
1118
      rval.closed_size    = 0;
 
1119
      rval.deferred_size  = 0;
 
1120
      rval.conflicts_size = 0;
 
1121
 
 
1122
      rval.solutions_exhausted = false;
 
1123
    }
 
1124
 
 
1125
  return rval;
 
1126
}
 
1127
 
 
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)
 
1131
{
 
1132
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1133
  if(solution_num < solutions.size())
 
1134
    return solutions[solution_num]->get_solution();
 
1135
 
 
1136
  while(solution_num >= solutions.size())
 
1137
    {
 
1138
      sol_l.release();
 
1139
 
 
1140
      try
 
1141
        {
 
1142
          generic_solution<aptitude_universe> sol = resolver->find_next_solution(max_steps, &visited_packages);
 
1143
 
 
1144
          sol_l.acquire();
 
1145
 
 
1146
          bool is_keep_all_solution =
 
1147
            (sol.get_choices() == resolver->get_keep_all_solution());
 
1148
 
 
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();
 
1154
          sol_l.release();
 
1155
        }
 
1156
      catch(const InterruptedException &e)
 
1157
        {
 
1158
          ticks_since_last_solution += e.get_steps();
 
1159
          throw e;
 
1160
        }
 
1161
      catch(NoMoreTime)
 
1162
        {
 
1163
          ticks_since_last_solution += max_steps;
 
1164
          throw NoMoreTime();
 
1165
        }
 
1166
      catch(NoMoreSolutions)
 
1167
        {
 
1168
          throw NoMoreSolutions();
 
1169
        }
 
1170
      catch(cwidget::util::Exception &e)
 
1171
        {
 
1172
          sol_l.acquire();
 
1173
          solution_search_aborted = true;
 
1174
          solution_search_abort_msg = e.errmsg();
 
1175
          throw;
 
1176
        }
 
1177
    }
 
1178
 
 
1179
  return solutions[solution_num]->get_solution();
 
1180
}
 
1181
 
 
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.
 
1187
 */
 
1188
class solution_return_continuation : public resolver_manager::background_continuation
 
1189
{
 
1190
  const generic_solution<aptitude_universe> * &sol;
 
1191
  std::string &abort_msg;
 
1192
  bool &oot;
 
1193
  bool &oos;
 
1194
  cwidget::threads::mutex &m;
 
1195
  cwidget::threads::condition &c;
 
1196
public:
 
1197
  solution_return_continuation(const generic_solution<aptitude_universe> * &_sol,
 
1198
                               std::string &_abort_msg,
 
1199
                               bool &_oot,
 
1200
                               bool &_oos,
 
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)
 
1204
  {
 
1205
  }
 
1206
 
 
1207
  void success(const generic_solution<aptitude_universe> &result)
 
1208
  {
 
1209
    cwidget::threads::mutex::lock l(m);
 
1210
 
 
1211
    sol = &result;
 
1212
    c.wake_all();
 
1213
  }
 
1214
 
 
1215
  void no_more_time()
 
1216
  {
 
1217
    cwidget::threads::mutex::lock l(m);
 
1218
 
 
1219
    oot = true;
 
1220
    c.wake_all();
 
1221
  }
 
1222
 
 
1223
  void no_more_solutions()
 
1224
  {
 
1225
    cwidget::threads::mutex::lock l(m);
 
1226
    oos = true;
 
1227
    c.wake_all();
 
1228
  }
 
1229
 
 
1230
  void interrupted()
 
1231
  {
 
1232
    // Should never happen, since we hold the big lock.
 
1233
    abort();
 
1234
  }
 
1235
 
 
1236
  void aborted(const std::string &errmsg)
 
1237
  {
 
1238
    cwidget::threads::mutex::lock l(m);
 
1239
 
 
1240
    sol = NULL;
 
1241
    abort_msg = errmsg;
 
1242
    c.wake_all();
 
1243
  }
 
1244
};
 
1245
 
 
1246
/** \brief Sadly, we can't easily save the real exception and reuse it
 
1247
 *  :(.
 
1248
 */
 
1249
class SolutionSearchAbortException : public cwidget::util::Exception
 
1250
{
 
1251
  std::string msg;
 
1252
 
 
1253
public:
 
1254
  SolutionSearchAbortException(const std::string &_msg)
 
1255
  {
 
1256
    msg = _msg;
 
1257
  }
 
1258
 
 
1259
  std::string errmsg() const
 
1260
  {
 
1261
    return msg;
 
1262
  }
 
1263
};
 
1264
 
 
1265
const aptitude_resolver::solution &resolver_manager::get_solution(unsigned int solution_num,
 
1266
                                                                  int max_steps)
 
1267
{
 
1268
  cwidget::threads::mutex::lock l(mutex);
 
1269
 
 
1270
  eassert(resolver);
 
1271
 
 
1272
  {
 
1273
    cwidget::threads::mutex::lock l2(solutions_mutex);
 
1274
    if(solution_num < solutions.size())
 
1275
      return *solutions[solution_num]->get_solution();
 
1276
  }
 
1277
 
 
1278
 
 
1279
  const generic_solution<aptitude_universe> *sol = NULL;
 
1280
  std::string abort_msg;
 
1281
  bool oot = false;
 
1282
  bool oos = false;
 
1283
  cwidget::threads::mutex m;
 
1284
  cwidget::threads::condition c;
 
1285
 
 
1286
  {
 
1287
    boost::shared_ptr<background_continuation> k;
 
1288
    k.reset(new solution_return_continuation(sol, abort_msg,
 
1289
                                             oot, oos, m, c));
 
1290
    get_solution_background(solution_num, max_steps, k,
 
1291
                            &inline_continuation_trampoline);
 
1292
  }
 
1293
  l.release();
 
1294
 
 
1295
  cwidget::threads::mutex::lock cond_l(m);
 
1296
 
 
1297
  while(!sol && !oot && !oos)
 
1298
    c.wait(cond_l);
 
1299
 
 
1300
  if(oot)
 
1301
    throw NoMoreTime();
 
1302
  else if(oos)
 
1303
    throw NoMoreSolutions();
 
1304
  else if(sol == NULL)
 
1305
    throw SolutionSearchAbortException(abort_msg);
 
1306
 
 
1307
  return *sol;
 
1308
}
 
1309
 
 
1310
bool resolver_manager::get_is_keep_all_solution(unsigned int solution_num,
 
1311
                                                int max_steps)
 
1312
{
 
1313
  cwidget::threads::mutex::lock l(mutex);
 
1314
 
 
1315
  get_solution(solution_num, max_steps);
 
1316
 
 
1317
  {
 
1318
    cwidget::threads::mutex::lock l2(solutions_mutex);
 
1319
    eassert(solution_num < solutions.size());
 
1320
 
 
1321
    return solutions[solution_num]->get_is_keep_all_solution();;
 
1322
  }
 
1323
}
 
1324
 
 
1325
void resolver_manager::get_solution_background(unsigned int solution_num,
 
1326
                                               int max_steps,
 
1327
                                               const boost::shared_ptr<background_continuation> &k,
 
1328
                                               post_thunk_f post_thunk)
 
1329
{
 
1330
  cwidget::threads::mutex::lock l(mutex);
 
1331
 
 
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);
 
1335
 
 
1336
  eassert(resolver_exists());
 
1337
 
 
1338
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1339
  if(solution_num < solutions.size())
 
1340
    {
 
1341
      const generic_solution<aptitude_universe> *sol = solutions[solution_num]->get_solution();
 
1342
      sol_l.release();
 
1343
 
 
1344
      k->success(*sol);
 
1345
      return;
 
1346
    }
 
1347
  sol_l.release();
 
1348
 
 
1349
 
 
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();
 
1353
}
 
1354
 
 
1355
class blocking_continuation : public resolver_manager::background_continuation
 
1356
{
 
1357
  /** The real continuation */
 
1358
  boost::shared_ptr<resolver_manager::background_continuation> k;
 
1359
 
 
1360
  /** The solution for which we are searching. */
 
1361
  unsigned int solution_num;
 
1362
 
 
1363
  /** The channel through which the result should be announced. */
 
1364
  cwidget::threads::box<bool> &result_box;
 
1365
 
 
1366
  /** The number of steps to try searching for a solution after this if
 
1367
   *  time runs out.
 
1368
   */
 
1369
  int remaining_steps;
 
1370
 
 
1371
  /** The manager associated with this continuation. */
 
1372
  resolver_manager &m;
 
1373
 
 
1374
  /** \brief How to invoke thunks safely. */
 
1375
  post_thunk_f post_thunk;
 
1376
 
 
1377
public:
 
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)
 
1387
  {
 
1388
  }
 
1389
 
 
1390
  void success(const generic_solution<aptitude_universe> &sol)
 
1391
  {
 
1392
    sigc::slot<void> success_slot =
 
1393
      sigc::bind(sigc::mem_fun(*k,
 
1394
                               &background_continuation::success),
 
1395
                 sol);
 
1396
 
 
1397
    post_thunk(make_keepalive_slot(success_slot, k));
 
1398
    result_box.put(true);
 
1399
  }
 
1400
 
 
1401
  void no_more_solutions()
 
1402
  {
 
1403
    sigc::slot<void> no_more_solutions_slot =
 
1404
      sigc::mem_fun(*k, &background_continuation::no_more_solutions);
 
1405
 
 
1406
    post_thunk(make_keepalive_slot(no_more_solutions_slot, k));
 
1407
    result_box.put(true);
 
1408
  }
 
1409
 
 
1410
  void no_more_time()
 
1411
  {
 
1412
    m.get_solution_background(solution_num, remaining_steps, k, post_thunk);
 
1413
    k.reset();
 
1414
    result_box.put(false);
 
1415
  }
 
1416
 
 
1417
  void interrupted()
 
1418
  {
 
1419
    // Give up and run in the background.
 
1420
    m.get_solution_background(solution_num, remaining_steps, k, post_thunk);
 
1421
    k.reset();
 
1422
    result_box.put(false);
 
1423
  }
 
1424
 
 
1425
  void aborted(const std::string &errmsg)
 
1426
  {
 
1427
    sigc::slot<void> aborted_slot =
 
1428
      sigc::bind(sigc::mem_fun(*k, &background_continuation::aborted),
 
1429
                 errmsg);
 
1430
 
 
1431
    post_thunk(make_keepalive_slot(aborted_slot, k));
 
1432
    result_box.put(true);
 
1433
  }
 
1434
};
 
1435
 
 
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)
 
1440
{
 
1441
  cwidget::threads::mutex::lock l(mutex);
 
1442
  background_suspender bs(*this);
 
1443
 
 
1444
  undo_group *undo = new undo_group;
 
1445
  (resolver->*action)(t, undo);
 
1446
  if(undo->empty())
 
1447
    delete undo;
 
1448
  else
 
1449
    undos->add_item(undo);
 
1450
 
 
1451
  actions_since_last_solution.push_back(act);
 
1452
 
 
1453
  l.release();
 
1454
  bs.unsuspend();
 
1455
  state_changed();
 
1456
}
 
1457
 
 
1458
void resolver_manager::reject_break_holds()
 
1459
{
 
1460
  cwidget::threads::mutex::lock l(mutex);
 
1461
  background_suspender bs(*this);
 
1462
 
 
1463
  std::auto_ptr<undo_group> undo(new undo_group);
 
1464
 
 
1465
  for(aptitude_universe::package_iterator pi = resolver->get_universe().packages_begin();
 
1466
      !pi.end(); ++pi)
 
1467
    {
 
1468
      const aptitude_universe::package p = *pi;
 
1469
 
 
1470
      for(aptitude_universe::package::version_iterator vi = p.versions_begin(); !vi.end(); ++vi)
 
1471
        {
 
1472
          const aptitude_universe::version v = *vi;
 
1473
          if(resolver->is_break_hold(v))
 
1474
            {
 
1475
              actions_since_last_solution.push_back(resolver_interaction::RejectVersion(v));
 
1476
              reject_version(v);
 
1477
            }
 
1478
        }
 
1479
    }
 
1480
 
 
1481
  if(!undo->empty())
 
1482
    undos->add_item(undo.release());
 
1483
 
 
1484
  l.release();
 
1485
  bs.unsuspend();
 
1486
  state_changed();
 
1487
}
 
1488
 
 
1489
void resolver_manager::reject_version(const aptitude_resolver_version &ver)
 
1490
{
 
1491
  resolver_manipulation(ver, &aptitude_resolver::reject_version,
 
1492
                        resolver_interaction::RejectVersion(ver));
 
1493
  version_accept_reject_changed(ver);
 
1494
}
 
1495
 
 
1496
void resolver_manager::unreject_version(const aptitude_resolver_version &ver)
 
1497
{
 
1498
  resolver_manipulation(ver, &aptitude_resolver::unreject_version,
 
1499
                        resolver_interaction::UnRejectVersion(ver));
 
1500
  version_accept_reject_changed(ver);
 
1501
}
 
1502
 
 
1503
bool resolver_manager::is_rejected(const aptitude_resolver_version &ver)
 
1504
{
 
1505
  cwidget::threads::mutex::lock l(mutex);
 
1506
  eassert(resolver);
 
1507
 
 
1508
  return resolver->is_rejected(ver);
 
1509
}
 
1510
 
 
1511
void resolver_manager::mandate_version(const aptitude_resolver_version &ver)
 
1512
{
 
1513
  resolver_manipulation(ver, &aptitude_resolver::mandate_version,
 
1514
                        resolver_interaction::MandateVersion(ver));
 
1515
  version_accept_reject_changed(ver);
 
1516
}
 
1517
 
 
1518
void resolver_manager::unmandate_version(const aptitude_resolver_version &ver)
 
1519
{
 
1520
  resolver_manipulation(ver, &aptitude_resolver::unmandate_version,
 
1521
                        resolver_interaction::UnMandateVersion(ver));
 
1522
  version_accept_reject_changed(ver);
 
1523
}
 
1524
 
 
1525
bool resolver_manager::is_mandatory(const aptitude_resolver_version &ver)
 
1526
{
 
1527
  cwidget::threads::mutex::lock l(mutex);
 
1528
  eassert(resolver);
 
1529
 
 
1530
  return resolver->is_mandatory(ver);
 
1531
}
 
1532
 
 
1533
void resolver_manager::harden_dep(const aptitude_resolver_dep &dep)
 
1534
{
 
1535
  resolver_manipulation(dep, &aptitude_resolver::harden,
 
1536
                        resolver_interaction::HardenDep(dep));
 
1537
  break_dep_accept_reject_changed(dep);
 
1538
}
 
1539
 
 
1540
void resolver_manager::unharden_dep(const aptitude_resolver_dep &dep)
 
1541
{
 
1542
  resolver_manipulation(dep, &aptitude_resolver::unharden,
 
1543
                        resolver_interaction::UnHardenDep(dep));
 
1544
  break_dep_accept_reject_changed(dep);
 
1545
}
 
1546
 
 
1547
bool resolver_manager::is_hardened(const aptitude_resolver_dep &dep)
 
1548
{
 
1549
  cwidget::threads::mutex::lock l(mutex);
 
1550
  eassert(resolver);
 
1551
 
 
1552
  return resolver->is_hardened(dep);
 
1553
}
 
1554
 
 
1555
void resolver_manager::approve_broken_dep(const aptitude_resolver_dep &dep)
 
1556
{
 
1557
  resolver_manipulation(dep, &aptitude_resolver::approve_break,
 
1558
                        resolver_interaction::ApproveBrokenDep(dep));
 
1559
  break_dep_accept_reject_changed(dep);
 
1560
}
 
1561
 
 
1562
void resolver_manager::unapprove_broken_dep(const aptitude_resolver_dep &dep)
 
1563
{
 
1564
  resolver_manipulation(dep, &aptitude_resolver::unapprove_break,
 
1565
                        resolver_interaction::UnApproveBrokenDep(dep));
 
1566
  break_dep_accept_reject_changed(dep);
 
1567
}
 
1568
 
 
1569
bool resolver_manager::is_approved_broken(const aptitude_resolver_dep &dep)
 
1570
{
 
1571
  cwidget::threads::mutex::lock l(mutex);
 
1572
  eassert(resolver != NULL);
 
1573
 
 
1574
  return resolver->is_approved_broken(dep);
 
1575
}
 
1576
 
 
1577
bool resolver_manager::has_undo_items()
 
1578
{
 
1579
  cwidget::threads::mutex::lock l(mutex);
 
1580
 
 
1581
  return undos->size() > 0;
 
1582
}
 
1583
 
 
1584
bool resolver_manager::undo()
 
1585
{
 
1586
  cwidget::threads::mutex::lock l(mutex);
 
1587
 
 
1588
  if(undos->size() > 0)
 
1589
    {
 
1590
      background_suspender bs(*this);
 
1591
 
 
1592
      undos->undo();
 
1593
 
 
1594
      actions_since_last_solution.push_back(resolver_interaction::Undo());
 
1595
 
 
1596
      bs.unsuspend();
 
1597
      l.release();
 
1598
 
 
1599
      state_changed();
 
1600
 
 
1601
      return true;
 
1602
    }
 
1603
  else
 
1604
    return false;
 
1605
}
 
1606
 
 
1607
void resolver_manager::select_solution(unsigned int solnum)
 
1608
{
 
1609
  cwidget::threads::mutex::lock l(mutex);
 
1610
 
 
1611
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1612
  if(solnum >= 0 && solnum <= solutions.size())
 
1613
    selected_solution = solnum;
 
1614
  sol_l.release();
 
1615
 
 
1616
  l.release();
 
1617
  state_changed();
 
1618
}
 
1619
 
 
1620
void resolver_manager::discard_error_information()
 
1621
{
 
1622
  cwidget::threads::mutex::lock l(mutex);
 
1623
 
 
1624
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1625
 
 
1626
  solution_search_aborted = false;
 
1627
  solution_search_abort_msg.clear();
 
1628
 
 
1629
  sol_l.release();
 
1630
  l.release();
 
1631
 
 
1632
  state_changed();
 
1633
}
 
1634
 
 
1635
void resolver_manager::select_next_solution()
 
1636
{
 
1637
  cwidget::threads::mutex::lock l(mutex);
 
1638
 
 
1639
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1640
  if(selected_solution < solutions.size())
 
1641
    ++selected_solution;
 
1642
  sol_l.release();
 
1643
 
 
1644
  l.release();
 
1645
  state_changed();
 
1646
}
 
1647
 
 
1648
void resolver_manager::select_previous_solution()
 
1649
{
 
1650
  cwidget::threads::mutex::lock l(mutex);
 
1651
 
 
1652
  cwidget::threads::mutex::lock sol_l(solutions_mutex);
 
1653
  if(selected_solution > 0)
 
1654
    --selected_solution;
 
1655
  sol_l.release();
 
1656
 
 
1657
  l.release();
 
1658
  state_changed();
 
1659
}
 
1660
 
 
1661
void resolver_manager::tweak_score(const pkgCache::PkgIterator &pkg,
 
1662
                                   const pkgCache::VerIterator &ver,
 
1663
                                   int score)
 
1664
{
 
1665
  cwidget::threads::mutex::lock l(mutex);
 
1666
  background_suspender bs(*this);
 
1667
 
 
1668
  eassert(resolver_exists());
 
1669
  eassert(resolver->fresh());
 
1670
 
 
1671
  aptitude_resolver_version res_ver;
 
1672
  if(ver.end())
 
1673
    res_ver = aptitude_resolver_version::make_removal(pkg, *cache_file);
 
1674
  else
 
1675
    res_ver = aptitude_resolver_version::make_install(ver, *cache_file);
 
1676
 
 
1677
  resolver->add_version_score(res_ver, score);
 
1678
}
 
1679
 
 
1680
void resolver_manager::dump(ostream &out)
 
1681
{
 
1682
  cwidget::threads::mutex::lock l(mutex);
 
1683
  background_suspender bs(*this);
 
1684
 
 
1685
  if(!resolver_exists())
 
1686
    return;
 
1687
 
 
1688
  // First, dump the universe.
 
1689
  dump_universe(resolver->get_universe(), out);
 
1690
 
 
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() << " ";
 
1697
 
 
1698
  resolver->dump_scores(out);
 
1699
 
 
1700
  out << "EXPECT ( " << aptcfg->FindI(PACKAGE "::ProblemResolver::StepLimit", defaultStepLimit) << " ANY )" << std::endl;
 
1701
}
 
1702
 
 
1703
void resolver_manager::maybe_start_solution_calculation(const boost::shared_ptr<background_continuation> &k,
 
1704
                                                        post_thunk_f post_thunk)
 
1705
{
 
1706
  state st = state_snapshot();
 
1707
 
 
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)
 
1713
    {
 
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);
 
1718
 
 
1719
      if(limit > 0)
 
1720
        get_solution_background(selected, limit, k, post_thunk);
 
1721
    }
 
1722
}
 
1723
 
 
1724
// Safe resolver logic:
 
1725
 
 
1726
class resolver_manager::safe_resolver_continuation : public resolver_manager::background_continuation
 
1727
{
 
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;
 
1733
 
 
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),
 
1739
      manager(_manager),
 
1740
      last_sol(_last_sol),
 
1741
      post_thunk(_post_thunk)
 
1742
  {
 
1743
  }
 
1744
 
 
1745
public:
 
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),
 
1750
      manager(_manager),
 
1751
      post_thunk(_post_thunk)
 
1752
  {
 
1753
  }
 
1754
 
 
1755
  void success(const generic_solution<aptitude_universe> &sol)
 
1756
  {
 
1757
    logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
 
1758
 
 
1759
    LOG_TRACE(logger, "safe_resolve_deps: got intermediate solution: " << sol);
 
1760
 
 
1761
    typedef generic_choice<aptitude_universe> choice;
 
1762
    typedef generic_choice_set<aptitude_universe> choice_set;
 
1763
 
 
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()))
 
1769
      {
 
1770
        // The solution changed; prepare the resolver for the next
 
1771
        // stage.
 
1772
 
 
1773
 
 
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)
 
1781
          {
 
1782
            switch(it->get_type())
 
1783
              {
 
1784
              case choice::install_version:
 
1785
                {
 
1786
                  const pkgCache::PkgIterator p(it->get_ver().get_pkg());
 
1787
 
 
1788
                  if(it->get_ver().get_ver() != p.CurrentVer())
 
1789
                    {
 
1790
                      LOG_DEBUG(logger,
 
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());
 
1794
                    }
 
1795
                  else
 
1796
                    {
 
1797
                      LOG_DEBUG(logger,
 
1798
                                "safe_resolve_deps: Not mandating " << it->get_ver()
 
1799
                                << ", since it is a hold.");
 
1800
                    }
 
1801
                }
 
1802
 
 
1803
                break;
 
1804
 
 
1805
              default:
 
1806
                // Nothing to do otherwise.
 
1807
                break;
 
1808
              }
 
1809
          }
 
1810
 
 
1811
 
 
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();
 
1816
 
 
1817
 
 
1818
        boost::shared_ptr<safe_resolver_continuation> safe_resolver_k;
 
1819
        safe_resolver_k.reset(new safe_resolver_continuation(k, manager, sol, post_thunk));
 
1820
 
 
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);
 
1826
 
 
1827
        const int limit = aptcfg->FindI(PACKAGE "::ProblemResolver::StepLimit", defaultStepLimit);
 
1828
 
 
1829
        manager->get_solution_background(manager->generated_solution_count(),
 
1830
                                         limit, safe_resolver_k, post_thunk);
 
1831
      }
 
1832
    else
 
1833
      {
 
1834
        // Internal error that should never happen, but try to survive
 
1835
        // if it does.
 
1836
        LOG_FATAL(logger,
 
1837
                  "safe_resolve_deps: Internal error: the resolver unexpectedly produced the same result twice: " << last_sol << " = " << sol);
 
1838
 
 
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);
 
1843
        else
 
1844
          LOG_WARN(logger, "safe_resolve_deps: should send the end solution to the real continuation, but it's NULL.");
 
1845
      }
 
1846
  }
 
1847
 
 
1848
  void no_more_solutions()
 
1849
  {
 
1850
    logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
 
1851
 
 
1852
    if(last_sol.valid())
 
1853
      {
 
1854
        LOG_TRACE(logger, "safe_resolve_deps: no more solutions; returning the last seen solution.");
 
1855
 
 
1856
        if(real_continuation.get() != NULL)
 
1857
          real_continuation->success(last_sol);
 
1858
        else
 
1859
          LOG_WARN(logger, "safe_resolve_deps: should return the last seen solution, but the continuation is NULL.");
 
1860
      }
 
1861
    else
 
1862
      {
 
1863
        LOG_TRACE(logger, "safe_resolve_deps: unable to find any solutions.");
 
1864
 
 
1865
        if(real_continuation.get() != NULL)
 
1866
          real_continuation->no_more_solutions();
 
1867
        else
 
1868
          LOG_WARN(logger, "safe_resolve_deps: should report that there are no solutions, but the continuation is NULL.");
 
1869
      }
 
1870
  }
 
1871
 
 
1872
  void no_more_time()
 
1873
  {
 
1874
    logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
 
1875
 
 
1876
    if(last_sol.valid())
 
1877
      {
 
1878
        LOG_TRACE(logger, "safe_resolve_deps: ran out of time searching for a solution; returning the last one that was computed.");
 
1879
 
 
1880
        if(real_continuation.get() != NULL)
 
1881
          real_continuation->success(last_sol);
 
1882
        else
 
1883
          LOG_WARN(logger, "safe_resolve_deps: should return the last seen solution, but the continuation is NULL.");
 
1884
      }
 
1885
    else
 
1886
      {
 
1887
        LOG_TRACE(logger, "safe_resolve_deps: ran out of time before finding any solutions.");
 
1888
 
 
1889
        if(real_continuation.get() != NULL)
 
1890
          real_continuation->no_more_time();
 
1891
        else
 
1892
          LOG_WARN(logger, "safe_resolve_deps: should report that we ran out of time, but the continuation is NULL.");
 
1893
      }
 
1894
  }
 
1895
 
 
1896
  void interrupted()
 
1897
  {
 
1898
    logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
 
1899
 
 
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!");
 
1903
  }
 
1904
 
 
1905
  void aborted(const std::string &errmsg)
 
1906
  {
 
1907
    logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolver());
 
1908
 
 
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);
 
1913
    else
 
1914
      LOG_WARN(logger, "safe_resolve_deps: should report that we were interrupted by an exception, but the continuation is NULL.  Exception: " << errmsg);
 
1915
  }
 
1916
};
 
1917
 
 
1918
void resolver_manager::setup_safe_resolver(bool no_new_installs, bool no_new_upgrades)
 
1919
{
 
1920
  eassert(resolver_exists());
 
1921
 
 
1922
  logging::LoggerPtr logger(Loggers::getAptitudeResolverSafeResolverSetup());
 
1923
 
 
1924
  LOG_TRACE(logger,
 
1925
            "setup_safe_resolver: Setting up the resolver state for safe dependency resolution.");
 
1926
 
 
1927
  reset_resolver();
 
1928
 
 
1929
  background_suspender bs(*this);
 
1930
 
 
1931
  for(pkgCache::PkgIterator p = (*cache_file)->PkgBegin();
 
1932
      !p.end(); ++p)
 
1933
    {
 
1934
      // Forbid the resolver from removing installed packages.
 
1935
      if(!p.CurrentVer().end())
 
1936
        {
 
1937
          aptitude_resolver_version remove_p =
 
1938
            aptitude_resolver_version::make_removal(p,
 
1939
                                                    *cache_file);
 
1940
 
 
1941
          LOG_DEBUG(logger,
 
1942
                    "setup_safe_resolver: Rejecting the removal of the package " << remove_p.get_package() << ".");
 
1943
 
 
1944
          reject_version(remove_p);
 
1945
        }
 
1946
 
 
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);
 
1952
 
 
1953
      // Forbid all real versions that aren't the current version or
 
1954
      // the candidate version.
 
1955
      for(pkgCache::VerIterator v = p.VersionList();
 
1956
          !v.end(); ++v)
 
1957
        {
 
1958
          // For our purposes, all half-unpacked etc states are
 
1959
          // installed.
 
1960
          const bool p_is_installed =
 
1961
            p->CurrentState != pkgCache::State::NotInstalled &&
 
1962
            p->CurrentState != pkgCache::State::ConfigFiles;
 
1963
 
 
1964
          bool p_will_install;
 
1965
          if(!p_initial_version.get_ver().end())
 
1966
            {
 
1967
              if(p->CurrentState == pkgCache::State::NotInstalled ||
 
1968
                 p->CurrentState == pkgCache::State::ConfigFiles)
 
1969
                p_will_install = true;
 
1970
              else
 
1971
                p_will_install = (p.CurrentVer() != p_initial_version.get_ver());
 
1972
            }
 
1973
          else
 
1974
            p_will_install = false;
 
1975
 
 
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);
 
1979
 
 
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))
 
1987
            {
 
1988
              aptitude_resolver_version p_v =
 
1989
                aptitude_resolver_version::make_install(v, *cache_file);
 
1990
 
 
1991
              if(logger->isEnabledFor(logging::DEBUG_LEVEL))
 
1992
                {
 
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).");
 
1999
                }
 
2000
 
 
2001
              reject_version(p_v);
 
2002
            }
 
2003
        }
 
2004
    }
 
2005
}
 
2006
 
 
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)
 
2010
{
 
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),
 
2013
                                   post_thunk);
 
2014
}
 
2015