1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
4 * Copyright (C) 2000-2002 Ximian, Inc.
5 * Copyright (C) 2005 SUSE Linux Products GmbH
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.
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.
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
22 #include "zypp/solver/detail/Resolver.h"
23 #include "zypp/solver/detail/Helper.h"
25 #include "zypp/CapSet.h"
26 #include "zypp/base/Logger.h"
27 #include "zypp/base/String.h"
28 #include "zypp/base/Gettext.h"
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"
38 /////////////////////////////////////////////////////////////////////////
40 { ///////////////////////////////////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////
43 { /////////////////////////////////////////////////////////////////
44 Arch defaultArchitecture();
45 /////////////////////////////////////////////////////////////////
46 } // namespace zypp_detail
47 ///////////////////////////////////////////////////////////////////
49 ///////////////////////////////////////////////////////////////////////
51 { /////////////////////////////////////////////////////////////////////
52 /////////////////////////////////////////////////////////////////////
54 { ///////////////////////////////////////////////////////////////////
58 IMPL_PTR_TYPE(Resolver);
60 static const unsigned MAX_SECOND_RUNS( 3 );
61 static const unsigned MAX_VALID_SOLUTIONS( 50 );
62 static const unsigned TIMOUT_SECOND_RUN( 30 );
64 static PoolItemSet triggeredSolution; // only the latest state of an item is interesting
65 // for the pool. Documents already inserted items.
67 //---------------------------------------------------------------------------
71 int operator() (PoolItem_Ref p1,
72 PoolItem_Ref p2) const
73 { return compareByNVRA(p1.resolvable(),p2.resolvable()) < 0; }
78 Resolver::dumpOn( std::ostream & os ) const
80 return os << "<resolver/>";
83 // Generating a system resolvable in the pool in order to trigger
84 // modaliases and hals
85 void assertSystemResObjectInPool()
87 ResPool pool( getZYpp()->pool() );
88 if ( pool.byKindBegin<SystemResObject>()
89 == pool.byKindEnd<SystemResObject>() )
91 // SystemResObject is missing in the pool ==> insert
93 store.insert( SystemResObject::instance() );
94 getZYpp()->addResolvables( store, true ); // true = is installed
98 if ( ! pool.byKindBegin<SystemResObject>()
99 ->status().setLock( true, ResStatus::USER ) )
101 WAR << "Unable to set SystemResObject to lock" << endl;
105 //---------------------------------------------------------------------------
107 Resolver::Resolver (const ResPool & pool)
109 , _timeout_seconds (0)
110 , _maxSolverPasses (0)
113 , _tryAllPossibilities (false)
114 , _valid_solution_count (0)
115 , _best_context (NULL)
116 , _establish_context (NULL)
118 , _architecture( zypp_detail::defaultArchitecture() )
119 , _forceResolve (false)
120 , _upgradeMode (false)
121 , _preferHighestVersion (true)
126 Resolver::~Resolver()
130 //---------------------------------------------------------------------------
133 Resolver::pool (void) const
139 Resolver::reset (void)
143 _initial_items.clear();
145 _items_to_install.clear();
146 _items_to_remove.clear();
147 _items_to_verify.clear();
148 _items_to_establish.clear();
151 _extra_conflicts.clear();
153 _pending_queues.clear();
154 _pruned_queues.clear();
155 _complete_queues.clear();
156 _deferred_queues.clear();
157 _invalid_queues.clear();
159 _valid_solution_count = 0;
161 _best_context = NULL;
168 Resolver::context (void) const
170 if (_best_context) return _best_context;
171 if (_invalid_queues.empty()) return NULL;
172 ResolverQueue_Ptr invalid = _invalid_queues.front();
173 return invalid->context();
176 void Resolver::dumpTaskList(const PoolItemList &install, const PoolItemList &remove )
178 for (PoolItemList::const_iterator iter = install.begin();
179 iter != install.end(); iter++) {
180 DBG << " to_install " << *iter << endl;
182 for (PoolItemList::const_iterator iter = remove.begin();
183 iter != remove.end(); iter++) {
184 DBG << " to_remove " << *iter << endl;
189 //---------------------------------------------------------------------------
192 Resolver::addSubscribedSource (Source_Ref source)
194 _subscribed.insert(source);
198 Resolver::addPoolItemToInstall (PoolItem_Ref item)
201 for (PoolItemList::const_iterator iter = _items_to_remove.begin();
202 iter != _items_to_remove.end(); iter++) {
204 _items_to_remove.remove(*iter);
210 _items_to_install.push_back (item);
211 _items_to_install.unique ();
217 Resolver::addPoolItemsToInstallFromList (PoolItemList & rl)
219 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
220 addPoolItemToInstall (*iter);
226 Resolver::addPoolItemToRemove (PoolItem_Ref item)
229 for (PoolItemList::const_iterator iter = _items_to_install.begin();
230 iter != _items_to_install.end(); iter++) {
232 _items_to_install.remove(*iter);
238 _items_to_remove.push_back (item);
239 _items_to_remove.unique ();
245 Resolver::addPoolItemsToRemoveFromList (PoolItemList & rl)
247 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
248 addPoolItemToRemove (*iter);
253 Resolver::addPoolItemToLockUninstalled (PoolItem_Ref item)
255 _items_to_lockUninstalled.push_back (item);
256 _items_to_lockUninstalled.unique ();
261 Resolver::addPoolItemToEstablish (PoolItem_Ref item)
263 _items_to_establish.push_back (item);
268 Resolver::addPoolItemsToEstablishFromList (PoolItemList & rl)
270 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
271 addPoolItemToEstablish (*iter);
277 Resolver::addPoolItemToVerify (PoolItem_Ref item)
280 /** Order PoolItems based on name and edition only. */
282 /** 'less then' based on name and edition */
283 bool operator()( PoolItem_Ref lhs, PoolItem_Ref rhs ) const
285 int res = lhs->name().compare( rhs->name() );
287 return res == -1; // lhs < rhs ?
288 // here: lhs == rhs, so compare edition:
289 return lhs->edition() < rhs->edition();
294 _items_to_verify.push_back (item);
296 #warning Should order by name (and probably edition since with zypp we could have multiple editions installed in parallel)
297 // _items_to_verify.sort (order); //(GCompareFunc) rc_item_compare_name);
302 Resolver::addExtraCapability (const Capability & capability)
304 _extra_caps.insert (capability);
309 Resolver::addExtraConflict (const Capability & capability)
311 _extra_conflicts.insert (capability);
316 Resolver::addIgnoreConflict (const PoolItem_Ref item,
317 const Capability & capability)
319 _ignoreConflicts.insert(make_pair(item, capability));
324 Resolver::addIgnoreRequires (const PoolItem_Ref item,
325 const Capability & capability)
327 _ignoreRequires.insert(make_pair(item, capability));
331 Resolver::addIgnoreObsoletes (const PoolItem_Ref item,
332 const Capability & capability)
334 _ignoreObsoletes.insert(make_pair(item, capability));
338 Resolver::addIgnoreInstalledItem (const PoolItem_Ref item)
340 _ignoreInstalledItem.push_back (item);
344 Resolver::addIgnoreArchitectureItem (const PoolItem_Ref item)
346 _ignoreArchitectureItem.push_back (item);
350 //---------------------------------------------------------------------------
352 struct UndoTransact : public resfilter::PoolItemFilterFunctor
354 ResStatus::TransactByValue resStatus;
355 UndoTransact ( const ResStatus::TransactByValue &status)
359 bool operator()( PoolItem_Ref item ) // only transacts() items go here
361 item.status().resetTransact( resStatus );// clear any solver/establish transactions
367 struct DoTransact : public resfilter::PoolItemFilterFunctor
369 ResStatus::TransactByValue resStatus;
370 DoTransact ( const ResStatus::TransactByValue &status)
374 bool operator()( PoolItem_Ref item ) // only transacts() items go here
376 item.status().setTransact( true, resStatus );
382 struct VerifySystem : public resfilter::PoolItemFilterFunctor
386 VerifySystem (Resolver & r)
390 bool operator()( PoolItem_Ref provider )
392 resolver.addPoolItemToVerify (provider);
398 Resolver::verifySystem (bool considerNewHardware)
400 UndoTransact resetting (ResStatus::APPL_HIGH);
402 _DEBUG ("Resolver::verifySystem() " << (considerNewHardware ? "consider new hardware":""));
404 invokeOnEach ( _pool.begin(), _pool.end(),
405 resfilter::ByTransact( ), // Resetting all transcations
406 functor::functorRef<bool,PoolItem>(resetting) );
408 VerifySystem info (*this);
410 invokeOnEach( pool().byKindBegin( ResTraits<Package>::kind ),
411 pool().byKindEnd( ResTraits<Package>::kind ),
412 resfilter::ByInstalled ( ),
413 functor::functorRef<bool,PoolItem>(info) );
415 invokeOnEach( pool().byKindBegin( ResTraits<Pattern>::kind ),
416 pool().byKindEnd( ResTraits<Pattern>::kind ),
417 resfilter::ByInstalled ( ),
418 functor::functorRef<bool,PoolItem>(info) );
423 bool success = false;
425 if (considerNewHardware) {
426 // evaluate all Freshens/Supplements and solve
427 success = freshenPool(false) && bestContext() && bestContext()->isValid();
430 success = resolveDependencies (); // do solve only
433 DoTransact setting (ResStatus::APPL_HIGH);
435 invokeOnEach ( _pool.begin(), _pool.end(),
436 resfilter::ByTransact( ),
437 functor::functorRef<bool,PoolItem>(setting) );
443 //---------------------------------------------------------------------------
445 // copy marked item from solution back to pool
446 // if data != NULL, set as APPL_LOW (from establishPool())
449 solution_to_pool (PoolItem_Ref item, const ResStatus & status, void *data)
451 if (triggeredSolution.find(item) != triggeredSolution.end()) {
452 _XDEBUG("solution_to_pool(" << item << ") is already in the pool --> skip");
456 triggeredSolution.insert(item);
458 // resetting transaction only
459 item.status().resetTransact((data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
463 if (status.isToBeInstalled()) {
464 r = item.status().setToBeInstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
465 _XDEBUG("solution_to_pool(" << item << ", " << status << ") install !" << r);
467 else if (status.isToBeUninstalledDueToUpgrade()) {
468 r = item.status().setToBeUninstalledDueToUpgrade( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
469 _XDEBUG("solution_to_pool(" << item << ", " << status << ") upgrade !" << r);
471 else if (status.isToBeUninstalled()) {
472 r = item.status().setToBeUninstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
473 _XDEBUG("solution_to_pool(" << item << ", " << status << ") remove !" << r);
475 else if (status.isIncomplete()
476 || status.isNeeded()) {
477 r = item.status().setIncomplete();
478 _XDEBUG("solution_to_pool(" << item << ", " << status << ") incomplete !" << r);
480 else if (status.isUnneeded()) {
481 r = item.status().setUnneeded();
482 _XDEBUG("solution_to_pool(" << item << ", " << status << ") unneeded !" << r);
484 else if (status.isSatisfied()) {
485 r = item.status().setSatisfied();
486 _XDEBUG("solution_to_pool(" << item << ", " << status << ") satisfied !" << r);
488 _XDEBUG("solution_to_pool(" << item << ", " << status << ") unchanged !");
494 //---------------------------------------------------------------------------
497 struct EstablishState
501 EstablishState (Resolver & r)
505 bool operator()( PoolItem_Ref provider )
507 resolver.addPoolItemToEstablish (provider);
514 Resolver::establishState( ResolverContext_Ptr context )
516 _DEBUG( "Resolver::establishState ()" );
517 typedef list<Resolvable::Kind> KindList;
518 static KindList ordered;
519 if (ordered.empty()) {
520 ordered.push_back (ResTraits<zypp::Atom>::kind);
521 ordered.push_back (ResTraits<zypp::Message>::kind);
522 ordered.push_back (ResTraits<zypp::Script>::kind);
523 ordered.push_back (ResTraits<zypp::Patch>::kind);
524 ordered.push_back (ResTraits<zypp::Pattern>::kind);
525 ordered.push_back (ResTraits<zypp::Product>::kind);
529 context = new ResolverContext(_pool, _architecture);
531 context->setEstablishing (true);
532 context->setIgnoreCababilities (_ignoreConflicts,
535 _ignoreInstalledItem,
536 _ignoreArchitectureItem);
537 context->setForceResolve( _forceResolve );
538 context->setEstablishContext( _establish_context );
539 context->setPreferHighestVersion ( _preferHighestVersion );
540 context->setUpgradeMode( _upgradeMode );
542 for (KindList::const_iterator iter = ordered.begin(); iter != ordered.end(); iter++) {
543 const Resolvable::Kind kind = *iter;
545 _XDEBUG( "establishing state for kind " << kind.asString() );
547 //world()->foreachResItemByKind (kind, trial_establish_cb, this);
549 EstablishState info (*this);
551 invokeOnEach( pool().byKindBegin( kind ),
552 pool().byKindEnd( kind ),
553 functor::functorRef<bool,PoolItem>(info) );
556 resolveDependencies( context );
561 context->setEstablishing (false);
563 _best_context = context;
564 _establish_context = context;
571 Resolver::establishPool ()
573 MIL << "Resolver::establishPool()" << endl;
575 establishState (); // establish !
576 ResolverContext_Ptr solution = bestContext();
578 if (solution) { // copy solution back to pool
579 triggeredSolution.clear();
580 solution->foreachMarked (solution_to_pool, (void *)1); // as APPL_LOW
583 ERR << "establishState did not return a bestContext" << endl;
591 //---------------------------------------------------------------------------
594 typedef map<string, PoolItem_Ref> FreshenMap;
596 // add item to itemmap
597 // check for item with same name and only keep
598 // best architecture, best version
601 addToFreshen( PoolItem_Ref item, FreshenMap & itemmap )
603 FreshenMap::iterator it = itemmap.find( item->name() );
604 if (it != itemmap.end()) { // item with same name found
605 int cmp = it->second->arch().compare( item->arch() );
606 if (cmp < 0) { // new item has better arch
609 else if (cmp == 0) { // new item has equal arch
610 if (it->second->edition().compare( item->edition() ) < 0) {
611 it->second = item; // new item has better edition
616 itemmap[item->name()] = item;
629 bool operator()( PoolItem_Ref item)
631 CapSet freshens( item->dep( Dep::FRESHENS ) );
632 if (!freshens.empty()) {
633 addToFreshen( item, itemmap );
635 else { // if no freshens, look at supplements
636 // Also regarding supplements e.g. in order to recognize
637 // modalias dependencies. Bug #163140
638 CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
639 if (!supplements.empty()) {
640 addToFreshen( item, itemmap );
649 Resolver::freshenState( ResolverContext_Ptr context,
650 bool resetAfterSolve )
652 _DEBUG( "Resolver::freshenState ()" );
655 context = new ResolverContext( _pool, _architecture );
657 context->setEstablishing( true );
658 context->setIgnoreCababilities( _ignoreConflicts,
661 _ignoreInstalledItem,
662 _ignoreArchitectureItem );
663 context->setForceResolve( _forceResolve );
664 context->setEstablishContext( _establish_context );
665 context->setPreferHighestVersion( _preferHighestVersion );
666 context->setUpgradeMode( _upgradeMode );
670 // collect items to be established
672 invokeOnEach( pool().byKindBegin( ResTraits<zypp::Package>::kind ),
673 pool().byKindEnd( ResTraits<zypp::Package>::kind ),
674 functor::functorRef<bool,PoolItem>(info) );
676 // schedule all collected items for establish
678 for (FreshenMap::iterator it = info.itemmap.begin(); it != info.itemmap.end(); ++it) {
679 addPoolItemToEstablish( it->second );
683 resolveDependencies( context );
685 if (resetAfterSolve) {
687 context->setEstablishing( false );
688 _best_context = context;
696 Resolver::freshenPool (bool resetAfterSolve)
698 MIL << "Resolver::freshenPool()" << endl;
700 freshenState (NULL, resetAfterSolve); // establish all packages with freshens; (NULL)= no initial context
701 ResolverContext_Ptr solution = bestContext();
703 if (solution) { // copy solution back to pool
704 triggeredSolution.clear();
705 solution->foreachMarked (solution_to_pool, (void *)1); // as APPL_LOW
708 ERR << "freshenState did not return a bestContext" << endl;
715 //---------------------------------------------------------------------------
718 Resolver::resolveDependencies (const ResolverContext_Ptr context)
721 time_t t_start, t_now;
723 MIL << "Resolver::resolveDependencies()" << endl;
725 _pending_queues.clear();
726 _pruned_queues.clear();
727 _complete_queues.clear();
728 _deferred_queues.clear();
729 _invalid_queues.clear();
730 _valid_solution_count = 0;
731 _best_context = NULL;
733 #warning local items disabled
735 bool have_local_items = false;
737 /* Walk through are list of to-be-installed packages and see if any of them are local. */
739 for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
740 if ((*iter)->local()) {
741 have_local_items = true;
746 World_Ptr the_world = world();
747 StoreWorld_Ptr local_world = NULL;
748 MultiWorld_Ptr local_multiworld = NULL;
750 Channel_Ptr local_channel = NULL;
752 if (have_local_items) {
753 local_multiworld = new MultiWorld();
754 local_world = new StoreWorld();
756 local_channel = new Channel ("", "Local ResItems", "@local", "");
758 local_world->addChannel (local_channel);
760 local_multiworld->addSubworld (local_world);
761 local_multiworld->addSubworld (the_world);
763 the_world = local_multiworld;
767 // create initial_queue
769 ResolverQueue_Ptr initial_queue = new ResolverQueue(_pool, _architecture, context);
771 // adding "external" provides, the the requirements will be ignored
772 IgnoreMap ignoreRequires = _ignoreRequires;
773 ResPool::AdditionalCapSet additionalCapSet = pool().additionaProvide();
774 for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
775 it != additionalCapSet.end(); it++) {
776 CapSet cset = it->second;
777 for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
778 ignoreRequires.insert(make_pair(PoolItem_Ref(), *cit));
782 // Initialize all ignoring dependencies
783 initial_queue->context()->setIgnoreCababilities (_ignoreConflicts,
786 _ignoreInstalledItem,
787 _ignoreArchitectureItem);
788 initial_queue->context()->setForceResolve( _forceResolve );
789 initial_queue->context()->setEstablishContext( _establish_context );
790 initial_queue->context()->setPreferHighestVersion( _preferHighestVersion );
791 initial_queue->context()->setUpgradeMode( _upgradeMode );
792 initial_queue->context()->setTryAllPossibilities( _tryAllPossibilities );
794 /* If this is a verify, we do a "soft resolution" */
796 initial_queue->context()->setVerifying( _verifying );
798 /* Add extra items. */
800 for (QueueItemList::const_iterator iter = _initial_items.begin(); iter != _initial_items.end(); iter++) {
801 initial_queue->addItem (*iter);
804 for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
805 PoolItem_Ref r = *iter;
807 #warning local items disabled
809 /* Add local packages to our dummy channel. */
811 assert (local_channel != NULL);
812 ResItem_Ptr r1 = const_pointer_cast<ResItem>(r);
813 r1->setChannel (local_channel);
814 local_world->addPoolItem_Ref (r);
817 initial_queue->addPoolItemToInstall (r);
820 for (PoolItemList::const_iterator iter = _items_to_remove.begin(); iter != _items_to_remove.end(); iter++) {
822 initial_queue->addPoolItemToRemove (*iter, true /* remove-only mode */);
824 // Checking old dependencies for packages which will be updated.
825 // E.g. foo provides a dependecy which foo-new does not provides anymore.
826 // So check, if there is a packages installed which requires foo.
827 // Testcase exercise-bug150844-test.xml
828 // Testcase Bug156439-test.xml
829 initial_queue->addPoolItemToRemove (*iter, false /* no remove-only mode */);
832 for (PoolItemList::const_iterator iter = _items_to_verify.begin(); iter != _items_to_verify.end(); iter++) {
833 initial_queue->addPoolItemToVerify (*iter);
836 for (PoolItemList::const_iterator iter = _items_to_establish.begin(); iter != _items_to_establish.end(); iter++) {
837 initial_queue->addPoolItemToEstablish (*iter);
840 for (CapSet::const_iterator iter = _extra_caps.begin(); iter != _extra_caps.end(); iter++) {
841 initial_queue->addExtraCapability (*iter);
844 // adding "external" requires
845 additionalCapSet = pool().additionalRequire();
846 for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
847 it != additionalCapSet.end(); it++) {
848 CapSet cset = it->second;
849 for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
850 initial_queue->addExtraCapability (*cit);
854 for (CapSet::const_iterator iter = _extra_conflicts.begin(); iter != _extra_conflicts.end(); iter++) {
855 initial_queue->addExtraConflict (*iter);
858 // adding "external" conflicts
859 additionalCapSet = pool().additionaConflict();
860 for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
861 it != additionalCapSet.end(); it++) {
862 CapSet cset = it->second;
863 for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
864 initial_queue->addExtraConflict (*cit);
868 // Adding System resolvable
869 assertSystemResObjectInPool();
871 _XDEBUG( "Initial Queue: [" << *initial_queue << "]" );
873 if (initial_queue->isEmpty()) {
874 INT << "Empty Queue, nothing to resolve" << endl;
875 _best_context = context; // Taking old context
879 _best_context = NULL;
881 _pending_queues.push_front (initial_queue);
885 while (!_pending_queues.empty()) {
887 _DEBUG( "Pend " << (long) _pending_queues.size()
888 << " / Cmpl " << (long) _complete_queues.size()
889 << " / Prun " << (long) _pruned_queues.size()
890 << " / Defr " << (long) _deferred_queues.size()
891 << " / Invl " << (long) _invalid_queues.size() );
893 if (_timeout_seconds > 0) {
895 if (difftime (t_now, t_start) > _timeout_seconds) {
897 MIL << "Timeout " << _timeout_seconds << " seconds reached"
898 << " -> exit" << endl;
902 if (_maxSolverPasses > 0) {
903 if (_maxSolverPasses <= _complete_queues.size() +
904 _pruned_queues.size() +
905 _deferred_queues.size() +
906 _invalid_queues.size()) {
908 MIL << "Max solver runs ( " << _maxSolverPasses
909 << " ) reached -> exit" << endl;
914 if (_best_context != NULL
915 && _complete_queues.size() >= MAX_VALID_SOLUTIONS) {
916 MIL << "Max VALID solver runs ( " << MAX_VALID_SOLUTIONS
917 << " ) reached -> exit" << endl;
921 ResolverQueue_Ptr queue = _pending_queues.front();
922 _pending_queues.pop_front();
923 ResolverContext_Ptr context = queue->context();
927 if (queue->isInvalid ()) {
929 _XDEBUG( "Invalid Queue\n" );
930 _invalid_queues.push_back(queue);
932 } else if (queue->isEmpty ()) {
934 _XDEBUG( "Empty Queue\n" );
936 _complete_queues.push_back(queue);
938 ++_valid_solution_count;
940 /* Compare this solution to our previous favorite. In the case of a tie,
941 the first solution wins --- yeah, I know this is lame, but it shouldn't
942 be an issue too much of the time. */
944 if (_best_context == NULL
945 || _best_context->compare (context) < 0)
947 _best_context = context;
950 } else if (_best_context != NULL
951 && _best_context->partialCompare (context) > 0) {
953 /* If we aren't currently as good as our previous best complete solution,
954 this solution gets pruned. */
956 _XDEBUG( "PRUNED!" );
958 _pruned_queues.push_back(queue);
962 /* If our queue is isn't empty and isn't invalid, that can only mean
963 one thing: we are down to nothing but branches. */
965 queue->splitFirstBranch (_pending_queues, _deferred_queues);
968 /* If we have run out of pending queues w/o finding any solutions,
969 and if we have deferred queues, make the first deferred queue
972 if (_pending_queues.empty()
973 && _complete_queues.empty()
974 && !_deferred_queues.empty()) {
975 _pending_queues.push_back(_deferred_queues.front());
978 _DEBUG("Pend " << (long) _pending_queues.size()
979 << " / Cmpl " << (long) _complete_queues.size()
980 << " / Prun " << (long) _pruned_queues.size()
981 << " / Defr " << (long) _deferred_queues.size()
982 << " / Invl " << (long) _invalid_queues.size() );
984 return _best_context && _best_context->isValid();
988 //----------------------------------------------------------------------------
994 UndoTransact info(ResStatus::APPL_LOW);
995 MIL << "*** undo ***" << endl;
996 invokeOnEach ( _pool.begin(), _pool.end(),
997 resfilter::ByTransact( ), // collect transacts from Pool to resolver queue
998 functor::functorRef<bool,PoolItem>(info) );
999 // These conflict should be ignored of the concering item
1000 _ignoreConflicts.clear();
1001 // These requires should be ignored of the concering item
1002 _ignoreRequires.clear();
1003 // These obsoletes should be ignored of the concering item
1004 _ignoreObsoletes.clear();
1005 // Ignore architecture of the item
1006 _ignoreArchitecture.clear();
1007 // Ignore the status "installed" of the item
1008 _ignoreInstalledItem.clear();
1009 // Ignore the architecture of the item
1010 _ignoreArchitectureItem.clear();
1016 //----------------------------------------------------------------------------
1019 struct CollectTransact : public resfilter::PoolItemFilterFunctor
1021 Resolver & resolver;
1023 CollectTransact (Resolver & r)
1027 bool operator()( PoolItem_Ref item ) // only transacts() items go here
1029 ResStatus status = item.status();
1030 _XDEBUG( "CollectTransact(" << item << ")" );
1031 bool by_solver = (status.isBySolver() || status.isByApplLow());
1034 _XDEBUG("Resetting " << item );
1035 item.status().resetTransact( ResStatus::APPL_LOW );// clear any solver/establish transactions
1036 return true; // back out here, dont re-queue former solver result
1039 if (status.isToBeInstalled()) {
1040 resolver.addPoolItemToInstall(item); // -> install!
1042 if (status.isToBeUninstalled()) {
1043 resolver.addPoolItemToRemove(item); // -> remove !
1045 if (status.isIncomplete()) { // incomplete (re-install needed)
1046 PoolItem_Ref reinstall = Helper::findReinstallItem (resolver.pool(), item);
1048 MIL << "Reinstall " << reinstall << " for incomplete " << item << endl;
1049 resolver.addPoolItemToInstall(reinstall); // -> install!
1052 WAR << "Can't find " << item << " for re-installation" << endl;
1056 if (status.isLocked()
1057 && status.isUninstalled()) {
1058 // This item could be selected by solver in a former run. Now it
1059 // is locked. So we will have to evaluate a new solver run.
1060 resolver.addPoolItemToLockUninstalled (item);
1069 show_pool( ResPool pool )
1072 static bool full_pool_shown = true;
1074 _XDEBUG( "---------------------------------------" );
1075 for (ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it, ++count) {
1077 if (!full_pool_shown // show item if not shown all before
1078 || it->status().transacts() // or transacts
1079 || !it->status().isUndetermined()) // or established status
1081 _DEBUG( count << ": " << *it );
1084 _XDEBUG( "---------------------------------------" );
1085 full_pool_shown = true;
1088 // This function loops over the pool and grabs
1089 // all item.status().transacts() and item.status().byUser()
1090 // It clears all previous bySolver() states also
1092 // Every toBeInstalled is passed to zypp::solver:detail::Resolver.addPoolItemToInstall()
1093 // Every toBeUninstalled is passed to zypp::solver:detail::Resolver.addPoolItemToRemove()
1095 // Then zypp::solver:detail::Resolver.resolveDependencies() is called.
1097 // zypp::solver:detail::Resolver then returns a ResolverContext via bestContext() which
1098 // describes the best solution. If bestContext() is NULL, no solution was found.
1100 // ResolverContext has a foreachMarked() iterator function which loops over all
1101 // items of the solutions. These must be written back to the pool.
1105 Resolver::resolvePool( bool tryAllPossibilities )
1107 ResolverContext_Ptr saveContext = _best_context;
1108 CollectTransact info (*this);
1110 // cleanup before next run
1113 bool saveTryAllPossibilities = _tryAllPossibilities;
1115 if (tryAllPossibilities) {
1116 _tryAllPossibilities = tryAllPossibilities;
1119 if (_tryAllPossibilities) {
1120 MIL << "================================================================"
1122 MIL << "Solver run with ALL possibilities"
1124 if (_maxSolverPasses <= 0)
1125 _maxSolverPasses = MAX_SECOND_RUNS;
1126 if (_timeout_seconds <= 0)
1127 _timeout_seconds = TIMOUT_SECOND_RUN;
1129 MIL << "But no longer than " << MAX_SECOND_RUNS << " runs or "
1130 << TIMOUT_SECOND_RUN << " seconds" << endl;
1131 MIL << "================================================================" << endl;
1136 MIL << "Resolver::resolvePool()" << endl;
1137 _XDEBUG( "Pool before resolve" );
1141 invokeOnEach ( _pool.begin(), _pool.end(),
1142 resfilter::ByTransact( ), // collect transacts from Pool to resolver queue
1143 functor::functorRef<bool,PoolItem>(info) );
1145 invokeOnEach ( _pool.begin(), _pool.end(),
1146 resfilter::ByLock( ), // collect locks from Pool to resolver queue
1147 functor::functorRef<bool,PoolItem>(info) );
1148 // List of installing/removing items of the complete run (not regarding a recycled solver run)
1149 PoolItemList _completeItems_to_install = _items_to_install;
1150 PoolItemList _completeItems_to_remove = _items_to_remove;
1151 PoolItemList _completeItems_to_lockUninstalled = _items_to_lockUninstalled;
1153 // We have to find a valid context in order to recycle it.
1154 saveContext = contextPool.findContext (_items_to_install, _items_to_remove, _items_to_lockUninstalled);
1155 // _items_to_install, _items_to_remove contains addition items which has been selected but are
1156 // not solved with that context. They will be solved now.
1157 // If we have not found any former fitting context, saveContext is NULL. So the solver
1158 // make a complete run
1160 if (saveContext != NULL) {
1161 // create a new context in order not overwriting the old
1162 saveContext = new ResolverContext (saveContext->pool(), saveContext->architecture(), saveContext);
1163 saveContext->setTryAllPossibilities( true );
1166 bool have_solution = resolveDependencies (saveContext); // resolve !
1168 if (have_solution) { // copy solution back to pool
1169 MIL << "Have solution, copying back to pool" << endl;
1170 ResolverContext_Ptr solution = bestContext();
1171 triggeredSolution.clear();
1172 solution->foreachMarked (solution_to_pool, NULL);
1174 _XDEBUG( "Pool after resolve" );
1177 // insert best_context in ContextPool for further solver runs
1178 contextPool.addContext( solution,_completeItems_to_install, _completeItems_to_remove, _completeItems_to_lockUninstalled);
1182 MIL << "!!! Have NO solution !!! Additional solver information:" << endl;
1184 for (ResolverQueueList::iterator iter = _invalid_queues.begin();
1185 iter != _invalid_queues.end(); iter++) {
1187 MIL << "-----------------------------------------------------------------" << endl;
1188 MIL << counter++ << ". failed queue:" << endl;
1189 ResolverQueue_Ptr invalid = *iter;
1190 invalid->context()->spewInfo ();
1191 MIL << *invalid->context() << endl;
1192 MIL << "-----------------------------------------------------------------" << endl;
1196 if (tryAllPossibilities) {
1197 _tryAllPossibilities = saveTryAllPossibilities; // reset to old value
1200 return have_solution;
1205 get_info_foreach_cb (ResolverInfo_Ptr info, void *data)
1207 list<string> *stringList = (list<string> *)data;
1208 stringList->push_back (info->message());
1212 // returns a string list of ResolverInfo of the LAST not valid solution
1213 std::list<std::string> Resolver::problemDescription( void ) const
1215 list<string> retList;
1216 if (_invalid_queues.empty()) return retList;
1217 ResolverQueue_Ptr invalid = _invalid_queues.front();
1218 invalid->context()->foreachInfo (PoolItem_Ref(), -1, get_info_foreach_cb, (void *)&retList);;
1224 // transact a single object
1225 // -> do a 'single step' resolving either installing or removing
1226 // required and recommended PoolItems
1229 Resolver::transactResObject( ResObject::constPtr robj, bool install,
1232 MIL << "transactResObject()" << endl;
1233 MIL << "is obsolete; use resolvePool() instead" << endl;
1240 Resolver::transactResKind( Resolvable::Kind kind )
1242 MIL << "transactResKind(" << kind << ")" << endl;
1243 MIL << "is obsolete; use resolvePool() instead" << endl;
1250 Resolver::transactReset( ResStatus::TransactByValue causer )
1252 MIL << "transactReset(" << causer << ")" << endl;
1253 MIL << "is obsolete; use resolvePool() instead" << endl;
1258 ///////////////////////////////////////////////////////////////////
1259 };// namespace detail
1260 /////////////////////////////////////////////////////////////////////
1261 /////////////////////////////////////////////////////////////////////
1262 };// namespace solver
1263 ///////////////////////////////////////////////////////////////////////
1264 ///////////////////////////////////////////////////////////////////////
1266 /////////////////////////////////////////////////////////////////////////