reduced too much verbosed logging; Bug 303971
[platform/upstream/libzypp.git] / zypp / solver / detail / Resolver.cc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* Resolver.cc
3  *
4  * Copyright (C) 2000-2002 Ximian, Inc.
5  * Copyright (C) 2005 SUSE Linux Products GmbH
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License,
9  * version 2, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19  * 02111-1307, USA.
20  */
21
22 #include "zypp/solver/detail/Resolver.h"
23 #include "zypp/solver/detail/Helper.h"
24
25 #include "zypp/CapSet.h"
26 #include "zypp/base/Logger.h"
27 #include "zypp/base/String.h"
28 #include "zypp/base/Gettext.h"
29
30 #include "zypp/base/Algorithm.h"
31 #include "zypp/ResPool.h"
32 #include "zypp/ResFilters.h"
33 #include "zypp/CapFilters.h"
34 #include "zypp/ZYppFactory.h"
35 #include "zypp/SystemResObject.h"
36 #include "zypp/solver/detail/ResolverInfoNeededBy.h"
37 #include "zypp/capability/FilesystemCap.h"
38
39
40 /////////////////////////////////////////////////////////////////////////
41 namespace zypp
42 { ///////////////////////////////////////////////////////////////////////
43   ///////////////////////////////////////////////////////////////////
44   namespace zypp_detail
45   { /////////////////////////////////////////////////////////////////
46     Arch defaultArchitecture();
47     /////////////////////////////////////////////////////////////////
48   } // namespace zypp_detail
49   ///////////////////////////////////////////////////////////////////
50
51   ///////////////////////////////////////////////////////////////////////
52   namespace solver
53   { /////////////////////////////////////////////////////////////////////
54     /////////////////////////////////////////////////////////////////////
55     namespace detail
56     { ///////////////////////////////////////////////////////////////////
57
58 using namespace std;
59
60 IMPL_PTR_TYPE(Resolver);
61
62 static const unsigned MAX_SECOND_RUNS( 3 );
63 static const unsigned MAX_VALID_SOLUTIONS( 10 );
64 static const unsigned TIMOUT_SECOND_RUN( 30 );
65
66 static PoolItemSet triggeredSolution;   // only the latest state of an item is interesting
67                                         // for the pool. Documents already inserted items.
68
69 //---------------------------------------------------------------------------
70
71 class compare_items {
72 public:
73     int operator() (PoolItem_Ref p1,
74                     PoolItem_Ref p2) const
75         { return compareByNVRA(p1.resolvable(),p2.resolvable()) < 0; }
76 };
77
78
79 std::ostream &
80 Resolver::dumpOn( std::ostream & os ) const
81 {
82     return os << "<resolver/>";
83 }
84
85 // Generating a system resolvable in the pool in order to trigger
86 // modaliases and hals
87 void assertSystemResObjectInPool()
88 {
89   ResPool pool( getZYpp()->pool() );
90   if ( pool.byKindBegin<SystemResObject>()
91        == pool.byKindEnd<SystemResObject>() )
92     {
93       // SystemResObject is missing in the pool ==> insert
94       ResStore store;
95       store.insert( SystemResObject::instance() );
96       getZYpp()->addResolvables( store, true ); // true = is installed
97     }
98
99   // set lock
100   if ( ! pool.byKindBegin<SystemResObject>()
101          ->status().setLock( true, ResStatus::USER ) )
102     {
103       WAR << "Unable to set SystemResObject to lock" << endl;
104     }
105 }
106
107 //---------------------------------------------------------------------------
108
109 Resolver::Resolver (const ResPool & pool)
110     : _pool (pool)
111     , _poolchanged( _pool.serial() )
112     , _timeout_seconds (0)
113     , _maxSolverPasses (0)
114     , _verifying (false)
115     , _testing (false)
116     , _tryAllPossibilities (false)
117     , _valid_solution_count (0)
118     , _best_context (NULL)
119     , _establish_context (NULL)
120     , _timed_out (false)
121     , _architecture( zypp_detail::defaultArchitecture() )
122     , _forceResolve (false)
123     , _upgradeMode (false)
124     , _preferHighestVersion (true)
125
126 {
127
128 }
129
130
131 Resolver::~Resolver()
132 {
133 }
134
135 //---------------------------------------------------------------------------
136
137 ResPool
138 Resolver::pool (void) const
139 {
140     return _pool;
141 }
142
143 void
144 Resolver::reset (bool resetValidResults, bool keepExtras )
145 {
146     _verifying = false;
147
148     _initial_items.clear();
149
150     _items_to_install.clear();
151     _items_to_remove.clear();
152     _items_to_verify.clear();
153     _items_to_establish.clear();
154
155     if (!keepExtras) {
156       _extra_caps.clear();
157       _extra_conflicts.clear();
158     }
159
160     _pending_queues.clear();
161     _pruned_queues.clear();
162     _complete_queues.clear();
163     _deferred_queues.clear();
164     _invalid_queues.clear();
165
166     _valid_solution_count = 0;
167
168     _best_context = NULL;
169     _timed_out = false;
170
171     _isInstalledBy.clear();
172     _installs.clear();
173
174     if (resetValidResults)
175         contextPool.reset();
176
177 }
178
179 //--------------------------------------------------------------------------------------------------
180 // Get more information about the solverrun
181 // Which item will be installed by another item or triggers an item for installation
182 typedef struct {
183     ItemCapKindMap isInstalledBy;
184     ItemCapKindMap installs;
185 } Collector;
186
187
188 static void
189 collector_cb_needed (ResolverInfo_Ptr info, void *data)
190 {
191     Collector *collector = (Collector *)data;
192     if (info->type() == RESOLVER_INFO_TYPE_NEEDED_BY) {
193         ResolverInfoNeededBy_constPtr needed_by = dynamic_pointer_cast<const ResolverInfoNeededBy>(info);
194         if (needed_by->items().size() >= 1) {
195             PoolItem_Ref item = info->affected();
196             PoolItemList itemList = needed_by->items();
197
198             for (PoolItemList::const_iterator iter = itemList.begin();
199                  iter != itemList.end(); iter++) {
200                 bool found = false;
201                 ItemCapKindMap::const_iterator pos = collector->isInstalledBy.find(item);
202                 while (pos != collector->isInstalledBy.end()
203                        && pos->first == item
204                        && !found) {
205                            ItemCapKind capKind = pos->second;
206                            if (capKind.item == *iter) found = true;
207                            pos++;
208                        }
209                 if (!found) {
210                     ItemCapKind capKind( *iter, needed_by->capability(), needed_by->capKind(), needed_by->initialInstallation() );
211                     collector->isInstalledBy.insert (make_pair( item, capKind));
212                 }
213                 found = false;
214                 pos = collector->installs.find (*iter);
215                 while (pos != collector->installs.end()
216                        && pos->first == *iter
217                        && !found) {
218                            ItemCapKind capKind = pos->second;
219                            if (capKind.item == item) found = true;
220                            pos++;
221                        }
222                 if (!found) {
223                     ItemCapKind capKindReverse( item, needed_by->capability(), needed_by->capKind(), needed_by->initialInstallation() );
224                     collector->installs.insert (make_pair( *iter, capKindReverse));
225                 }
226             }
227
228         }
229     }
230 }
231
232 void
233 Resolver::collectResolverInfo(void)
234 {
235     ResolverContext_Ptr collectContext = context(); // best context or failed context
236     if ( collectContext != NULL
237          && _isInstalledBy.empty()
238          && _installs.empty()) {
239         Collector collector;
240         collectContext->foreachInfo (PoolItem(), RESOLVER_INFO_PRIORITY_VERBOSE, collector_cb_needed, &collector, false); // do not merge information
241         _isInstalledBy = collector.isInstalledBy;
242         _installs = collector.installs;
243     }
244 }
245
246
247 const ItemCapKindList Resolver::isInstalledBy (const PoolItem_Ref item) {
248     ItemCapKindList ret;
249     collectResolverInfo();
250
251     for (ItemCapKindMap::const_iterator iter = _isInstalledBy.find(item); iter != _isInstalledBy.end();) {
252         ItemCapKind info = iter->second;
253         PoolItem_Ref iterItem = iter->first;
254         if (iterItem == item) {
255             ret.push_back(info);
256             iter++;
257         } else {
258             // exit
259             iter = _isInstalledBy.end();
260         }
261     }
262     return ret;
263 }
264
265 const ItemCapKindList Resolver::installs (const PoolItem_Ref item) {
266     ItemCapKindList ret;
267     collectResolverInfo();
268
269     for (ItemCapKindMap::const_iterator iter = _installs.find(item); iter != _installs.end();) {
270         ItemCapKind info = iter->second;
271         PoolItem_Ref iterItem = iter->first;
272         if (iterItem == item) {
273             ret.push_back(info);
274             iter++;
275         } else {
276             // exit
277             iter = _installs.end();
278         }
279     }
280     return ret;
281 }
282
283
284 //----------------------------------------------------------------------------------------------------
285 ResolverContext_Ptr
286 Resolver::context (void) const
287 {
288     if (_best_context) return _best_context;
289     if (_invalid_queues.empty()) return NULL;
290     ResolverQueue_Ptr invalid = _invalid_queues.front();
291     return invalid->context();
292 }
293
294 void  Resolver::dumpTaskList(const PoolItemList &install, const PoolItemList &remove )
295 {
296     for (PoolItemList::const_iterator iter = install.begin();
297          iter != install.end(); iter++) {
298         DBG << "    to_install " << *iter << endl;
299     }
300     for (PoolItemList::const_iterator iter = remove.begin();
301          iter != remove.end(); iter++) {
302         DBG << "    to_remove " << *iter << endl;
303     }
304 }
305
306
307 //---------------------------------------------------------------------------
308
309 void
310 Resolver::addSubscribedSource (Repository repo)
311 {
312     _subscribed.insert(repo);
313 }
314
315 void
316 Resolver::addPoolItemToInstall (PoolItem_Ref item)
317 {
318     bool found = false;
319     for (PoolItemList::const_iterator iter = _items_to_remove.begin();
320          iter != _items_to_remove.end(); iter++) {
321         if (*iter == item) {
322             _items_to_remove.remove(*iter);
323             found = true;
324             break;
325         }
326     }
327     if (!found) {
328         _items_to_install.push_back (item);
329         _items_to_install.unique ();
330     }
331 }
332
333
334 void
335 Resolver::addPoolItemsToInstallFromList (PoolItemList & rl)
336 {
337     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
338         addPoolItemToInstall (*iter);
339     }
340 }
341
342
343 void
344 Resolver::addPoolItemToRemove (PoolItem_Ref item)
345 {
346     bool found = false;
347     for (PoolItemList::const_iterator iter = _items_to_install.begin();
348          iter != _items_to_install.end(); iter++) {
349         if (*iter == item) {
350             _items_to_install.remove(*iter);
351             found = true;
352             break;
353         }
354     }
355     if (!found) {
356         _items_to_remove.push_back (item);
357         _items_to_remove.unique ();
358     }
359 }
360
361
362 void
363 Resolver::addPoolItemsToRemoveFromList (PoolItemList & rl)
364 {
365     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
366         addPoolItemToRemove (*iter);
367     }
368 }
369
370 void
371 Resolver::addPoolItemToLockUninstalled (PoolItem_Ref item)
372 {
373     _items_to_lockUninstalled.push_back (item);
374     _items_to_lockUninstalled.unique ();
375 }
376
377
378 void
379 Resolver::addPoolItemToEstablish (PoolItem_Ref item)
380 {
381     _items_to_establish.push_back (item);
382 }
383
384
385 void
386 Resolver::addPoolItemsToEstablishFromList (PoolItemList & rl)
387 {
388     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
389         addPoolItemToEstablish (*iter);
390     }
391 }
392
393
394 void
395 Resolver::addPoolItemToVerify (PoolItem_Ref item)
396 {
397 #if 0
398   /** Order PoolItems based on name and edition only. */
399   struct {
400     /** 'less then' based on name and edition */
401     bool operator()( PoolItem_Ref lhs, PoolItem_Ref rhs ) const
402     {
403       int res = lhs->name().compare( rhs->name() );
404       if ( res )
405         return res == -1; // lhs < rhs ?
406       // here: lhs == rhs, so compare edition:
407       return lhs->edition() < rhs->edition();
408     }
409   } order;
410 #endif
411
412     _items_to_verify.push_back (item);
413
414 #warning Should order by name (and probably edition since with zypp we could have multiple editions installed in parallel)
415 //    _items_to_verify.sort (order);                    //(GCompareFunc) rc_item_compare_name);
416 }
417
418
419 void
420 Resolver::addExtraCapability (const Capability & capability)
421 {
422     _extra_caps.insert (capability);
423 }
424
425
426 void
427 Resolver::addExtraConflict (const Capability & capability)
428 {
429     _extra_conflicts.insert (capability);
430 }
431
432
433 void
434 Resolver::addIgnoreConflict (const PoolItem_Ref item,
435                    const Capability & capability)
436 {
437     _ignoreConflicts.insert(make_pair(item, capability));
438 }
439
440
441 void
442 Resolver::addIgnoreRequires (const PoolItem_Ref item,
443                              const Capability & capability)
444 {
445     _ignoreRequires.insert(make_pair(item, capability));
446 }
447
448 void
449 Resolver::addIgnoreObsoletes (const PoolItem_Ref item,
450                               const Capability & capability)
451 {
452     _ignoreObsoletes.insert(make_pair(item, capability));
453 }
454
455 void
456 Resolver::addIgnoreInstalledItem (const PoolItem_Ref item)
457 {
458     _ignoreInstalledItem.push_back (item);
459 }
460
461 void
462 Resolver::addIgnoreArchitectureItem (const PoolItem_Ref item)
463 {
464     _ignoreArchitectureItem.push_back (item);
465 }
466
467 void
468 Resolver::addIgnoreVendorItem (const PoolItem_Ref item)
469 {
470     _ignoreVendorItem.push_back (item);
471 }
472
473 //---------------------------------------------------------------------------
474
475 struct UndoTransact : public resfilter::PoolItemFilterFunctor
476 {
477     ResStatus::TransactByValue resStatus;
478     UndoTransact ( const ResStatus::TransactByValue &status)
479         :resStatus(status)
480     { }
481
482     bool operator()( PoolItem_Ref item )                // only transacts() items go here
483     {
484         item.status().resetTransact( resStatus );// clear any solver/establish transactions
485         return true;
486     }
487 };
488
489
490 struct DoTransact : public resfilter::PoolItemFilterFunctor
491 {
492     ResStatus::TransactByValue resStatus;
493     DoTransact ( const ResStatus::TransactByValue &status)
494         :resStatus(status)
495     { }
496
497     bool operator()( PoolItem_Ref item )                // only transacts() items go here
498     {
499         item.status().setTransact( true, resStatus );
500         return true;
501     }
502 };
503
504
505 struct VerifySystem : public resfilter::PoolItemFilterFunctor
506 {
507     Resolver & resolver;
508
509     VerifySystem (Resolver & r)
510         : resolver (r)
511     { }
512
513     bool operator()( PoolItem_Ref provider )
514     {
515         resolver.addPoolItemToVerify (provider);
516         return true;
517     }
518 };
519
520 bool
521 Resolver::verifySystem (bool considerNewHardware)
522 {
523     UndoTransact resetting (ResStatus::APPL_HIGH);
524
525     _DEBUG ("Resolver::verifySystem() " << (considerNewHardware ? "consider new hardware":""));
526
527     invokeOnEach ( _pool.begin(), _pool.end(),
528                    resfilter::ByTransact( ),                    // Resetting all transcations
529                    functor::functorRef<bool,PoolItem>(resetting) );
530
531     VerifySystem info (*this);
532
533     invokeOnEach( pool().byKindBegin( ResTraits<Package>::kind ),
534                   pool().byKindEnd( ResTraits<Package>::kind ),
535                   resfilter::ByInstalled ( ),
536                   functor::functorRef<bool,PoolItem>(info) );
537
538     invokeOnEach( pool().byKindBegin( ResTraits<Pattern>::kind ),
539                   pool().byKindEnd( ResTraits<Pattern>::kind ),
540                   resfilter::ByInstalled ( ),
541                   functor::functorRef<bool,PoolItem>(info) );
542
543
544     _verifying = true;
545
546     bool success = false;
547
548     if (considerNewHardware) {
549         // evaluate all Freshens/Supplements and solve
550         success = freshenPool(false) && bestContext() && bestContext()->isValid();
551     }
552     else {
553         success = resolveDependencies (); // do solve only
554     }
555
556     DoTransact setting (ResStatus::APPL_HIGH);
557
558     invokeOnEach ( _pool.begin(), _pool.end(),
559                    resfilter::ByTransact( ),
560                    functor::functorRef<bool,PoolItem>(setting) );
561
562     return success;
563 }
564
565
566 //---------------------------------------------------------------------------
567
568 // copy marked item from solution back to pool
569 // if data != NULL, set as APPL_LOW (from establishPool())
570
571 static void
572 solution_to_pool (PoolItem_Ref item, const ResStatus & status, void *data)
573 {
574     if (triggeredSolution.find(item) != triggeredSolution.end()) {
575         _XDEBUG("solution_to_pool(" << item << ") is already in the pool --> skip");
576         return;
577     }
578
579     triggeredSolution.insert(item);
580
581     // resetting transaction only
582     item.status().resetTransact((data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
583
584     bool r;
585
586     if (status.isToBeInstalled()) {
587         r = item.status().setToBeInstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
588         _XDEBUG("solution_to_pool(" << item << ", " << status << ") install !" << r);
589     }
590     else if (status.isToBeUninstalledDueToUpgrade()) {
591         r = item.status().setToBeUninstalledDueToUpgrade( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
592         _XDEBUG("solution_to_pool(" << item << ", " << status << ") upgrade !" << r);
593     }
594     else if (status.isToBeUninstalled()) {
595         r = item.status().setToBeUninstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
596         _XDEBUG("solution_to_pool(" << item << ", " << status << ") remove !" << r);
597     }
598     else if (status.isIncomplete()
599              || status.isNeeded()) {
600         r = item.status().setIncomplete();
601         _XDEBUG("solution_to_pool(" << item << ", " << status << ") incomplete !" << r);
602     }
603     else if (status.isUnneeded()) {
604         r = item.status().setUnneeded();
605         _XDEBUG("solution_to_pool(" << item << ", " << status << ") unneeded !" << r);
606     }
607     else if (status.isSatisfied()) {
608         r = item.status().setSatisfied();
609         _XDEBUG("solution_to_pool(" << item << ", " << status << ") satisfied !" << r);
610     } else {
611         _XDEBUG("solution_to_pool(" << item << ", " << status << ") unchanged !");
612     }
613     return;
614 }
615
616
617 //---------------------------------------------------------------------------
618 // establish state
619
620 struct EstablishState
621 {
622     Resolver & resolver;
623
624     EstablishState (Resolver & r)
625         : resolver (r)
626     { }
627
628     bool operator()( PoolItem_Ref provider )
629     {
630         resolver.addPoolItemToEstablish (provider);
631         return true;
632     }
633 };
634
635
636 void
637 Resolver::establishState( ResolverContext_Ptr context )
638 {
639     _DEBUG( "Resolver::establishState ()" );
640     typedef list<Resolvable::Kind> KindList;
641     static KindList ordered;
642     if (ordered.empty()) {
643         ordered.push_back (ResTraits<zypp::Atom>::kind);
644         ordered.push_back (ResTraits<zypp::Message>::kind);
645         ordered.push_back (ResTraits<zypp::Script>::kind);
646         ordered.push_back (ResTraits<zypp::Patch>::kind);
647         ordered.push_back (ResTraits<zypp::Pattern>::kind);
648         ordered.push_back (ResTraits<zypp::Product>::kind);
649     }
650
651     if (context == NULL)
652         context = new ResolverContext(_pool, _architecture);
653
654     context->setEstablishing (true);
655     context->setIgnoreCababilities (_ignoreConflicts,
656                                     _ignoreRequires,
657                                     _ignoreObsoletes,
658                                     _ignoreInstalledItem,
659                                     _ignoreArchitectureItem,
660                                     _ignoreVendorItem);
661     context->setForceResolve( _forceResolve );
662     context->setEstablishContext( _establish_context );
663     context->setPreferHighestVersion ( _preferHighestVersion );
664     context->setUpgradeMode( _upgradeMode );
665
666     for (KindList::const_iterator iter = ordered.begin(); iter != ordered.end(); iter++) {
667         const Resolvable::Kind kind = *iter;
668
669         _XDEBUG( "establishing state for kind " << kind.asString() );
670
671         //world()->foreachResItemByKind (kind, trial_establish_cb, this);
672
673         EstablishState info (*this);
674
675         invokeOnEach( pool().byKindBegin( kind ),
676                       pool().byKindEnd( kind ),
677                       functor::functorRef<bool,PoolItem>(info) );
678
679         // process the queue
680         resolveDependencies( context );
681         reset( false, true ); //resetValidResults,keepExtras
682     }
683
684     context->setEstablishing (false);
685
686     _best_context = context;
687     _establish_context = context;
688
689     return;
690 }
691
692
693 bool
694 Resolver::establishPool ()
695 {
696     MIL << "Resolver::establishPool()" << endl;
697
698     establishState ();                                          // establish !
699     ResolverContext_Ptr solution = bestContext();
700
701     if (solution) {                                             // copy solution back to pool
702         triggeredSolution.clear();
703         solution->foreachMarked (solution_to_pool, (void *)1);  // as APPL_LOW
704     }
705     else {
706         ERR << "establishState did not return a bestContext" << endl;
707         return false;
708     }
709
710     return true;
711 }
712
713
714 //---------------------------------------------------------------------------
715 // freshen state
716
717 typedef map<string, PoolItem_Ref> FreshenMap;
718
719 // add item to itemmap
720 //  check for item with same name and only keep
721 //  best architecture, best version
722
723 static void
724 addToFreshen( PoolItem_Ref item, FreshenMap & itemmap )
725 {
726     FreshenMap::iterator it = itemmap.find( item->name() );
727     if (it != itemmap.end()) {                                  // item with same name found
728         int cmp = it->second->arch().compare( item->arch() );
729         if (cmp < 0) {                                          // new item has better arch
730             it->second = item;
731         }
732         else if (cmp == 0) {                                    // new item has equal arch
733             if (it->second->edition().compare( item->edition() ) < 0) {
734                 it->second = item;                              // new item has better edition
735             }
736         }
737     }
738     else {
739         itemmap[item->name()] = item;
740     }
741     return;
742 }
743
744
745 struct FreshenState
746 {
747     FreshenMap itemmap;
748
749     FreshenState()
750     { }
751
752     bool operator()( PoolItem_Ref item)
753     {
754         CapSet freshens( item->dep( Dep::FRESHENS ) );
755         if (!freshens.empty()) {
756             addToFreshen( item, itemmap );
757         }
758         else {                                  // if no freshens, look at supplements
759             // Also regarding supplements e.g. in order to recognize
760             // modalias dependencies. Bug #163140
761             CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
762             if (!supplements.empty()) {
763                 addToFreshen( item, itemmap );
764             }
765         }
766         return true;
767     }
768 };
769
770
771 void
772 Resolver::freshenState( ResolverContext_Ptr context,
773                         bool resetAfterSolve )
774 {
775     _DEBUG( "Resolver::freshenState ()" );
776
777     if (context == NULL)
778         context = new ResolverContext( _pool, _architecture );
779
780     context->setEstablishing( true );
781     context->setIgnoreCababilities( _ignoreConflicts,
782                                     _ignoreRequires,
783                                     _ignoreObsoletes,
784                                     _ignoreInstalledItem,
785                                     _ignoreArchitectureItem,
786                                     _ignoreVendorItem);
787     context->setForceResolve( _forceResolve );
788     context->setEstablishContext( _establish_context );
789     context->setPreferHighestVersion( _preferHighestVersion );
790     context->setUpgradeMode( _upgradeMode );
791
792     FreshenState info;
793
794     // collect items to be established
795
796     invokeOnEach( pool().byKindBegin( ResTraits<zypp::Package>::kind ),
797                       pool().byKindEnd( ResTraits<zypp::Package>::kind ),
798                       functor::functorRef<bool,PoolItem>(info) );
799
800     // schedule all collected items for establish
801
802     for (FreshenMap::iterator it = info.itemmap.begin(); it != info.itemmap.end(); ++it) {
803         addPoolItemToEstablish( it->second );
804     }
805
806     // process the queue
807     resolveDependencies( context );
808
809     if (resetAfterSolve) {
810         reset( false, true ); //resetValidResults,keepExtras
811         context->setEstablishing( false );
812         _best_context = context;
813     }
814
815     return;
816 }
817
818
819 bool
820 Resolver::freshenPool (bool resetAfterSolve)
821 {
822     MIL << "Resolver::freshenPool()" << endl;
823
824     freshenState (NULL, resetAfterSolve);       // establish all packages with freshens; (NULL)= no initial context
825     ResolverContext_Ptr solution = bestContext();
826
827     if (solution) {                                             // copy solution back to pool
828         triggeredSolution.clear();
829         solution->foreachMarked (solution_to_pool, (void *)1);  // as APPL_LOW
830     }
831     else {
832         ERR << "freshenState did not return a bestContext" << endl;
833         return false;
834     }
835
836     return true;
837 }
838
839 //---------------------------------------------------------------------------
840
841 struct FileSystemEstablishItem
842 {
843     Resolver & resolver;
844     
845     FileSystemEstablishItem (Resolver & r)
846         : resolver (r)
847     { }
848
849     // items with filecaps has to be evaluate again via establish
850
851     bool operator()( const CapAndItem & cai )
852     {
853         _XDEBUG( "QueueItemInstall::FileSystemEstablishItem (" << cai.item << ", " << cai.cap << ")");
854         resolver.addPoolItemToEstablish (cai.item);
855         return true;
856     }
857 };
858
859
860
861 bool
862 Resolver::resolveDependencies (const ResolverContext_Ptr context)
863 {
864
865     time_t t_start, t_now;
866
867     MIL << "Resolver::resolveDependencies()" << endl;
868
869     _pending_queues.clear();
870     _pruned_queues.clear();
871     _complete_queues.clear();
872     _deferred_queues.clear();
873     _invalid_queues.clear();
874     _valid_solution_count = 0;
875     _best_context = NULL;
876
877 #warning local items disabled
878 #if 0
879     bool have_local_items = false;
880
881     /* Walk through are list of to-be-installed packages and see if any of them are local. */
882
883     for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
884         if ((*iter)->local()) {
885             have_local_items = true;
886             break;
887         }
888     }
889
890     World_Ptr the_world = world();
891     StoreWorld_Ptr local_world = NULL;
892     MultiWorld_Ptr local_multiworld = NULL;
893
894     Channel_Ptr local_channel = NULL;
895
896     if (have_local_items) {
897         local_multiworld = new MultiWorld();
898         local_world = new StoreWorld();
899
900         local_channel = new Channel ("", "Local ResItems", "@local", "");
901
902         local_world->addChannel (local_channel);
903
904         local_multiworld->addSubworld (local_world);
905         local_multiworld->addSubworld (the_world);
906
907         the_world = local_multiworld;
908     }
909 #endif    
910
911     // Checking if we have to make additional establish concerning filesystem capabilities
912     FileSystemEstablishItem establish(*this);
913     Dep dep( Dep::SUPPLEMENTS);
914     invokeOnEach( pool().byCapabilityIndexBegin( "filesystem()", dep ), // begin()
915                           pool().byCapabilityIndexEnd( "filesystem()", dep ),   // end()
916                           functor::functorRef<bool,CapAndItem>( establish ) );
917
918     // create initial_queue
919
920     ResolverQueue_Ptr initial_queue = new ResolverQueue(_pool, _architecture, context);
921
922     // adding "external" provides, the the requirements will be ignored
923     IgnoreMap ignoreRequires = _ignoreRequires;
924     ResPool::AdditionalCapSet additionalCapSet = pool().additionaProvide();
925     for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
926          it != additionalCapSet.end(); it++) {
927         CapSet cset = it->second;
928         for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
929             ignoreRequires.insert(make_pair(PoolItem_Ref(), *cit));
930         }
931     }
932
933     // Initialize all ignoring dependencies
934     initial_queue->context()->setIgnoreCababilities (_ignoreConflicts,
935                                                      ignoreRequires,
936                                                      _ignoreObsoletes,
937                                                      _ignoreInstalledItem,
938                                                      _ignoreArchitectureItem,
939                                                      _ignoreVendorItem);
940     initial_queue->context()->setForceResolve( _forceResolve );
941     initial_queue->context()->setEstablishContext( _establish_context );
942     initial_queue->context()->setPreferHighestVersion( _preferHighestVersion );
943     initial_queue->context()->setUpgradeMode( _upgradeMode );
944     initial_queue->context()->setTryAllPossibilities( _tryAllPossibilities );
945
946     /* If this is a verify, we do a "soft resolution" */
947
948     initial_queue->context()->setVerifying( _verifying );
949
950     /* Add extra items. */
951
952     for (QueueItemList::const_iterator iter = _initial_items.begin(); iter != _initial_items.end(); iter++) {
953         initial_queue->addItem (*iter);
954     }
955
956     for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
957         PoolItem_Ref r = *iter;
958
959 #warning local items disabled
960 #if 0
961         /* Add local packages to our dummy channel. */
962         if (r->local()) {
963             assert (local_channel != NULL);
964             ResItem_Ptr r1 = const_pointer_cast<ResItem>(r);
965             r1->setChannel (local_channel);
966             local_world->addPoolItem_Ref (r);
967         }
968 #endif
969         initial_queue->addPoolItemToInstall (r);
970     }
971
972     for (PoolItemList::const_iterator iter = _items_to_remove.begin(); iter != _items_to_remove.end(); iter++) {
973         if (!_upgradeMode)
974             initial_queue->addPoolItemToRemove (*iter, true /* remove-only mode */);
975         else
976             //   Checking old dependencies for packages which will be updated.
977             //   E.g. foo provides a dependecy which foo-new does not provides anymore.
978             //   So check, if there is a packages installed which requires foo.
979             //   Testcase exercise-bug150844-test.xml
980             //   Testcase Bug156439-test.xml
981             initial_queue->addPoolItemToRemove (*iter, false /* no remove-only mode */);
982     }
983
984     for (PoolItemList::const_iterator iter = _items_to_verify.begin(); iter != _items_to_verify.end(); iter++) {
985         initial_queue->addPoolItemToVerify (*iter);
986     }
987
988     for (PoolItemList::const_iterator iter = _items_to_establish.begin(); iter != _items_to_establish.end(); iter++) {
989         initial_queue->addPoolItemToEstablish (*iter);
990     }
991
992     for (CapSet::const_iterator iter = _extra_caps.begin(); iter != _extra_caps.end(); iter++) {
993         initial_queue->addExtraCapability (*iter);
994     }
995
996     // adding "external" requires
997     additionalCapSet = pool().additionalRequire();
998     for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
999          it != additionalCapSet.end(); it++) {
1000         CapSet cset = it->second;
1001         for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
1002             initial_queue->addExtraCapability (*cit);
1003         }
1004     }
1005
1006     for (CapSet::const_iterator iter = _extra_conflicts.begin(); iter != _extra_conflicts.end(); iter++) {
1007         initial_queue->addExtraConflict (*iter);
1008     }
1009
1010     // adding "external" conflicts
1011     additionalCapSet = pool().additionaConflict();
1012     for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
1013          it != additionalCapSet.end(); it++) {
1014         CapSet cset = it->second;
1015         for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
1016             initial_queue->addExtraConflict (*cit);
1017         }
1018     }
1019
1020     // Adding System resolvable
1021     assertSystemResObjectInPool();
1022
1023     _XDEBUG( "Initial Queue: [" << *initial_queue << "]" );
1024
1025     if (initial_queue->isEmpty()) {
1026         INT << "Empty Queue, nothing to resolve" << endl;
1027         _best_context = context; // Taking old context
1028         return true;
1029     }
1030
1031     _best_context = NULL;
1032
1033     _pending_queues.push_front (initial_queue);
1034
1035     time (&t_start);
1036
1037     while (!_pending_queues.empty()) {
1038
1039         _DEBUG( "Pend " << (long) _pending_queues.size()
1040                 << " / Cmpl " << (long) _complete_queues.size()
1041                 << " / Prun " << (long) _pruned_queues.size()
1042                 << " / Defr " << (long) _deferred_queues.size()
1043                 << " / Invl " << (long) _invalid_queues.size() );
1044
1045         if (_timeout_seconds > 0) {
1046             time (&t_now);
1047             if (difftime (t_now, t_start) > _timeout_seconds) {
1048                 _timed_out = true;
1049                 MIL << "Timeout " << _timeout_seconds << " seconds reached"
1050                     << " -> exit" << endl;
1051                 break;
1052             }
1053         }
1054         if (_maxSolverPasses > 0) {
1055             if (_maxSolverPasses <= _complete_queues.size() +
1056                 _pruned_queues.size() +
1057                 _deferred_queues.size() +
1058                 _invalid_queues.size()) {
1059                 _timed_out = true;
1060                 MIL << "Max solver runs ( " << _maxSolverPasses
1061                     << " ) reached -> exit" << endl;
1062                 break;
1063             }
1064         }
1065
1066         if (_best_context != NULL
1067             && _complete_queues.size() >= MAX_VALID_SOLUTIONS) {
1068                 MIL << "Max VALID solver runs ( " << MAX_VALID_SOLUTIONS
1069                     << " ) reached -> exit" << endl;
1070                 break;
1071         }
1072
1073         ResolverQueue_Ptr queue = _pending_queues.front();
1074         _pending_queues.pop_front();
1075         ResolverContext_Ptr context = queue->context();
1076
1077         queue->process();
1078
1079         if (queue->isInvalid ()) {
1080
1081             _XDEBUG( "Invalid Queue\n" );
1082             _invalid_queues.push_back(queue);
1083
1084         } else if (queue->isEmpty ()) {
1085
1086             _XDEBUG( "Empty Queue\n" );
1087
1088             _complete_queues.push_back(queue);
1089
1090             ++_valid_solution_count;
1091
1092             /* Compare this solution to our previous favorite.  In the case of a tie,
1093                the first solution wins --- yeah, I know this is lame, but it shouldn't
1094                be an issue too much of the time. */
1095
1096             if (_best_context == NULL
1097                 || _best_context->compare (context) < 0)
1098             {
1099                 _best_context = context;
1100             }
1101
1102         } else if (_best_context != NULL
1103                    && _best_context->partialCompare (context) > 0) {
1104
1105             /* If we aren't currently as good as our previous best complete solution,
1106                this solution gets pruned. */
1107
1108             _XDEBUG( "PRUNED!" );
1109
1110             _pruned_queues.push_back(queue);
1111
1112         } else {
1113
1114             /* If our queue is isn't empty and isn't invalid, that can only mean
1115                one thing: we are down to nothing but branches. */
1116
1117             queue->splitFirstBranch (_pending_queues, _deferred_queues);
1118         }
1119
1120         /* If we have run out of pending queues w/o finding any solutions,
1121            and if we have deferred queues, make the first deferred queue
1122            pending. */
1123
1124         if (_pending_queues.empty()
1125             && _complete_queues.empty()
1126             && !_deferred_queues.empty()) {
1127             _pending_queues.push_back(_deferred_queues.front());
1128         }
1129     }
1130     _DEBUG("Pend " << (long) _pending_queues.size()
1131            << " / Cmpl " << (long) _complete_queues.size()
1132            << " / Prun " << (long) _pruned_queues.size()
1133            << " / Defr " << (long) _deferred_queues.size()
1134            << " / Invl " << (long) _invalid_queues.size() );
1135
1136     return _best_context && _best_context->isValid();
1137 }
1138
1139
1140 //----------------------------------------------------------------------------
1141 // undo
1142
1143 void
1144 Resolver::undo(void)
1145 {
1146     UndoTransact info(ResStatus::APPL_LOW);
1147     MIL << "*** undo ***" << endl;
1148     invokeOnEach ( _pool.begin(), _pool.end(),
1149                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
1150                    functor::functorRef<bool,PoolItem>(info) );
1151     // These conflict should be ignored of the concering item
1152     _ignoreConflicts.clear();
1153     // These requires should be ignored of the concering item
1154     _ignoreRequires.clear();
1155     // These obsoletes should be ignored of the concering item
1156     _ignoreObsoletes.clear();
1157     // Ignore architecture of the item
1158     _ignoreArchitecture.clear();
1159     // Ignore the status "installed" of the item
1160     _ignoreInstalledItem.clear();
1161     // Ignore the architecture of the item
1162     _ignoreArchitectureItem.clear();
1163     // Ignore the vendor of the item
1164     _ignoreVendorItem.clear();
1165
1166
1167     return;
1168 }
1169
1170 //----------------------------------------------------------------------------
1171 // resolvePool
1172
1173 struct CollectTransact : public resfilter::PoolItemFilterFunctor
1174 {
1175     Resolver & resolver;
1176
1177     CollectTransact (Resolver & r)
1178         : resolver (r)
1179     { }
1180
1181     bool operator()( PoolItem_Ref item )                // only transacts() items go here
1182     {
1183         ResStatus status = item.status();
1184         _XDEBUG( "CollectTransact(" << item << ")" );
1185         bool by_solver = (status.isBySolver() || status.isByApplLow());
1186
1187         if (by_solver) {
1188             _XDEBUG("Resetting " << item );
1189             item.status().resetTransact( ResStatus::APPL_LOW );// clear any solver/establish transactions
1190             return true;                                // back out here, dont re-queue former solver result
1191         }
1192
1193         if (status.isToBeInstalled()) {
1194             resolver.addPoolItemToInstall(item);        // -> install!
1195         }
1196         if (status.isToBeUninstalled()) {
1197             resolver.addPoolItemToRemove(item);         // -> remove !
1198         }
1199         if (status.isIncomplete()) {                    // incomplete (re-install needed)
1200             PoolItem_Ref reinstall = Helper::findReinstallItem (resolver.pool(), item);
1201             if (reinstall) {
1202                 MIL << "Reinstall " << reinstall << " for incomplete " << item << endl;
1203                 resolver.addPoolItemToInstall(reinstall);       // -> install!
1204             }
1205             else {
1206                 WAR << "Can't find " << item << " for re-installation" << endl;
1207             }
1208         }
1209
1210         if (status.isLocked()
1211             && status.isUninstalled()) {
1212             // This item could be selected by solver in a former run. Now it
1213             // is locked. So we will have to evaluate a new solver run.
1214             resolver.addPoolItemToLockUninstalled (item);
1215         }
1216
1217         return true;
1218     }
1219 };
1220
1221
1222 static void
1223 show_pool( ResPool pool )
1224 {
1225     int count = 1;
1226     static bool full_pool_shown = true;
1227
1228     _XDEBUG( "---------------------------------------" );
1229     for (ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it, ++count) {
1230
1231         if (!full_pool_shown                                    // show item if not shown all before
1232             || it->status().transacts()                         // or transacts
1233             || !it->status().isUndetermined())                  // or established status
1234         {
1235             _DEBUG( count << ": " << *it );
1236         }
1237     }
1238     _XDEBUG( "---------------------------------------" );
1239     full_pool_shown = true;
1240 }
1241
1242 //  This function loops over the pool and grabs
1243 //  all item.status().transacts() and item.status().byUser()
1244 //  It clears all previous bySolver() states also
1245 //
1246 //  Every toBeInstalled is passed to zypp::solver:detail::Resolver.addPoolItemToInstall()
1247 //  Every toBeUninstalled is passed to zypp::solver:detail::Resolver.addPoolItemToRemove()
1248 //
1249 //  Then zypp::solver:detail::Resolver.resolveDependencies() is called.
1250 //
1251 //  zypp::solver:detail::Resolver then returns a ResolverContext via bestContext() which
1252 //  describes the best solution. If bestContext() is NULL, no solution was found.
1253 //
1254 //  ResolverContext has a foreachMarked() iterator function which loops over all
1255 //  items of the solutions. These must be written back to the pool.
1256
1257
1258 bool
1259 Resolver::resolvePool( bool tryAllPossibilities )
1260 {
1261     ResolverContext_Ptr saveContext = _best_context;
1262     CollectTransact info (*this);
1263
1264     // cleanup before next run
1265     if ( _poolchanged.remember( _pool.serial() ) )
1266     {
1267         MIL << "pool has been CHANGED --> resetting solverresults" << endl;
1268         reset( true, true ); //resetValidResults,keepExtras     
1269     } else {
1270         reset( false, true ); //resetValidResults,keepExtras
1271     }
1272     
1273     bool saveTryAllPossibilities = _tryAllPossibilities;
1274
1275     if (tryAllPossibilities) {
1276         _tryAllPossibilities = tryAllPossibilities;
1277     }
1278
1279     if (_tryAllPossibilities) {
1280         MIL << "================================================================"
1281             << endl;
1282         MIL << "Solver run with ALL possibilities"
1283             << endl;
1284         if (_maxSolverPasses <= 0)
1285             _maxSolverPasses = MAX_SECOND_RUNS;
1286         if (_timeout_seconds <= 0)
1287             _timeout_seconds = TIMOUT_SECOND_RUN;
1288
1289         MIL << "But no longer than " << MAX_SECOND_RUNS << " runs or "
1290             << TIMOUT_SECOND_RUN << " seconds" << endl;
1291         MIL << "================================================================" << endl;
1292     }
1293
1294 #if 1
1295
1296     MIL << "Resolver::resolvePool()" << endl;
1297     _XDEBUG( "Pool before resolve" );
1298     show_pool( _pool );
1299
1300 #endif
1301     invokeOnEach ( _pool.begin(), _pool.end(),
1302                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
1303                    functor::functorRef<bool,PoolItem>(info) );
1304
1305     invokeOnEach ( _pool.begin(), _pool.end(),
1306                    resfilter::ByLock( ),                        // collect locks from Pool to resolver queue
1307                    functor::functorRef<bool,PoolItem>(info) );
1308     // List of installing/removing items of the complete run (not regarding a recycled solver run)
1309     PoolItemList _completeItems_to_install = _items_to_install;
1310     PoolItemList _completeItems_to_remove = _items_to_remove;
1311     PoolItemList _completeItems_to_lockUninstalled = _items_to_lockUninstalled;
1312
1313     // We have to find a valid context in order to recycle it.
1314     saveContext = contextPool.findContext (_items_to_install, _items_to_remove, _items_to_lockUninstalled);
1315     // _items_to_install, _items_to_remove contains addition items which has been selected but are
1316     // not solved with that context. They will be solved now.
1317     // If we have not found any former fitting context, saveContext is NULL. So the solver
1318     // make a complete run
1319
1320     if (saveContext != NULL) {
1321         // create a new context in order not overwriting the old
1322         saveContext = new ResolverContext (saveContext->pool(), saveContext->architecture(), saveContext);
1323         saveContext->setTryAllPossibilities( true );
1324     }
1325
1326     bool have_solution = resolveDependencies (saveContext);             // resolve !
1327
1328     if (have_solution) {                                        // copy solution back to pool
1329         MIL << "Have solution, copying back to pool" << endl;
1330         ResolverContext_Ptr solution = bestContext();
1331         triggeredSolution.clear();
1332         solution->foreachMarked (solution_to_pool, NULL);
1333 #if 1
1334         _XDEBUG( "Pool after resolve" );
1335         show_pool( _pool );
1336 #endif
1337         // insert best_context in ContextPool for further solver runs
1338         contextPool.addContext( solution,_completeItems_to_install, _completeItems_to_remove, _completeItems_to_lockUninstalled);
1339
1340     }
1341     else {
1342         MIL << "!!! Have NO solution !!!" << endl;      
1343 #if 0 // It takes too much memory for logging. Do not use it !
1344         MIL << "!!! Have NO solution !!! Additional solver information:" << endl;
1345         int counter = 0;
1346         for (ResolverQueueList::iterator iter = _invalid_queues.begin();
1347              iter != _invalid_queues.end(); iter++) {
1348             counter++;
1349             MIL << "-----------------------------------------------------------------" << endl;
1350             MIL << counter++ << ". failed queue:" << endl;
1351             ResolverQueue_Ptr invalid = *iter;
1352             invalid->context()->spewInfo (); No additional information needed here
1353             MIL << *invalid->context() << endl;
1354             MIL << "-----------------------------------------------------------------" << endl;
1355         }
1356 #endif
1357     }
1358
1359     if (tryAllPossibilities) {
1360         _tryAllPossibilities = saveTryAllPossibilities; // reset to old value
1361     }
1362
1363     return have_solution;
1364 }
1365
1366
1367 static void
1368 get_info_foreach_cb (ResolverInfo_Ptr info, void *data)
1369 {
1370     list<string> *stringList = (list<string> *)data;
1371     stringList->push_back (info->message());
1372 }
1373
1374
1375 // returns a string list of ResolverInfo of the LAST not valid solution
1376 std::list<std::string> Resolver::problemDescription( void ) const
1377 {
1378     list<string> retList;
1379     if (_invalid_queues.empty()) return retList;
1380     ResolverQueue_Ptr invalid = _invalid_queues.front();
1381     invalid->context()->foreachInfo (PoolItem_Ref(), -1, get_info_foreach_cb, (void *)&retList);;
1382     return retList;
1383 }
1384
1385
1386 //
1387 // transact a single object
1388 // -> do a 'single step' resolving either installing or removing
1389 //    required and recommended PoolItems
1390
1391 bool
1392 Resolver::transactResObject( ResObject::constPtr robj, bool install,
1393                              bool recursive)
1394 {
1395     MIL << "transactResObject()" << endl;
1396     MIL << "is obsolete; use resolvePool() instead" << endl;
1397
1398     return true;
1399 }
1400
1401
1402 bool
1403 Resolver::transactResKind( Resolvable::Kind kind )
1404 {
1405     MIL << "transactResKind(" << kind << ")" << endl;
1406     MIL << "is obsolete; use resolvePool() instead" << endl;
1407
1408     return true;
1409 }
1410
1411
1412 void
1413 Resolver::transactReset( ResStatus::TransactByValue causer )
1414 {
1415     MIL << "transactReset(" << causer << ")" << endl;
1416     MIL << "is obsolete; use resolvePool() instead" << endl;
1417
1418     return;
1419 }
1420
1421 ///////////////////////////////////////////////////////////////////
1422     };// namespace detail
1423     /////////////////////////////////////////////////////////////////////
1424     /////////////////////////////////////////////////////////////////////
1425   };// namespace solver
1426   ///////////////////////////////////////////////////////////////////////
1427   ///////////////////////////////////////////////////////////////////////
1428 };// namespace zypp
1429 /////////////////////////////////////////////////////////////////////////
1430