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"
36 #include "zypp/solver/detail/ResolverInfoNeededBy.h"
37 #include "zypp/capability/FilesystemCap.h"
40 /////////////////////////////////////////////////////////////////////////
42 { ///////////////////////////////////////////////////////////////////////
43 ///////////////////////////////////////////////////////////////////
45 { /////////////////////////////////////////////////////////////////
46 Arch defaultArchitecture();
47 /////////////////////////////////////////////////////////////////
48 } // namespace zypp_detail
49 ///////////////////////////////////////////////////////////////////
51 ///////////////////////////////////////////////////////////////////////
53 { /////////////////////////////////////////////////////////////////////
54 /////////////////////////////////////////////////////////////////////
56 { ///////////////////////////////////////////////////////////////////
60 IMPL_PTR_TYPE(Resolver);
62 static const unsigned MAX_SECOND_RUNS( 3 );
63 static const unsigned MAX_VALID_SOLUTIONS( 10 );
64 static const unsigned TIMOUT_SECOND_RUN( 30 );
66 static PoolItemSet triggeredSolution; // only the latest state of an item is interesting
67 // for the pool. Documents already inserted items.
69 //---------------------------------------------------------------------------
73 int operator() (PoolItem_Ref p1,
74 PoolItem_Ref p2) const
75 { return compareByNVRA(p1.resolvable(),p2.resolvable()) < 0; }
80 Resolver::dumpOn( std::ostream & os ) const
82 return os << "<resolver/>";
85 // Generating a system resolvable in the pool in order to trigger
86 // modaliases and hals
87 void assertSystemResObjectInPool()
89 ResPool pool( getZYpp()->pool() );
90 if ( pool.byKindBegin<SystemResObject>()
91 == pool.byKindEnd<SystemResObject>() )
93 // SystemResObject is missing in the pool ==> insert
95 store.insert( SystemResObject::instance() );
96 getZYpp()->addResolvables( store, true ); // true = is installed
100 if ( ! pool.byKindBegin<SystemResObject>()
101 ->status().setLock( true, ResStatus::USER ) )
103 WAR << "Unable to set SystemResObject to lock" << endl;
107 //---------------------------------------------------------------------------
109 Resolver::Resolver (const ResPool & pool)
111 , _poolchanged( _pool.serial() )
112 , _timeout_seconds (0)
113 , _maxSolverPasses (0)
116 , _tryAllPossibilities (false)
117 , _valid_solution_count (0)
118 , _best_context (NULL)
119 , _establish_context (NULL)
121 , _architecture( zypp_detail::defaultArchitecture() )
122 , _forceResolve (false)
123 , _upgradeMode (false)
124 , _preferHighestVersion (true)
131 Resolver::~Resolver()
135 //---------------------------------------------------------------------------
138 Resolver::pool (void) const
144 Resolver::reset (bool resetValidResults, bool keepExtras )
148 _initial_items.clear();
150 _items_to_install.clear();
151 _items_to_remove.clear();
152 _items_to_verify.clear();
153 _items_to_establish.clear();
157 _extra_conflicts.clear();
160 _pending_queues.clear();
161 _pruned_queues.clear();
162 _complete_queues.clear();
163 _deferred_queues.clear();
164 _invalid_queues.clear();
166 _valid_solution_count = 0;
168 _best_context = NULL;
171 _isInstalledBy.clear();
174 if (resetValidResults)
179 //--------------------------------------------------------------------------------------------------
180 // Get more information about the solverrun
181 // Which item will be installed by another item or triggers an item for installation
183 ItemCapKindMap isInstalledBy;
184 ItemCapKindMap installs;
189 collector_cb_needed (ResolverInfo_Ptr info, void *data)
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();
198 for (PoolItemList::const_iterator iter = itemList.begin();
199 iter != itemList.end(); iter++) {
201 ItemCapKindMap::const_iterator pos = collector->isInstalledBy.find(item);
202 while (pos != collector->isInstalledBy.end()
203 && pos->first == item
205 ItemCapKind capKind = pos->second;
206 if (capKind.item == *iter) found = true;
210 ItemCapKind capKind( *iter, needed_by->capability(), needed_by->capKind(), needed_by->initialInstallation() );
211 collector->isInstalledBy.insert (make_pair( item, capKind));
214 pos = collector->installs.find (*iter);
215 while (pos != collector->installs.end()
216 && pos->first == *iter
218 ItemCapKind capKind = pos->second;
219 if (capKind.item == item) found = true;
223 ItemCapKind capKindReverse( item, needed_by->capability(), needed_by->capKind(), needed_by->initialInstallation() );
224 collector->installs.insert (make_pair( *iter, capKindReverse));
233 Resolver::collectResolverInfo(void)
235 ResolverContext_Ptr collectContext = context(); // best context or failed context
236 if ( collectContext != NULL
237 && _isInstalledBy.empty()
238 && _installs.empty()) {
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;
247 const ItemCapKindList Resolver::isInstalledBy (const PoolItem_Ref item) {
249 collectResolverInfo();
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) {
259 iter = _isInstalledBy.end();
265 const ItemCapKindList Resolver::installs (const PoolItem_Ref item) {
267 collectResolverInfo();
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) {
277 iter = _installs.end();
284 //----------------------------------------------------------------------------------------------------
286 Resolver::context (void) const
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();
294 void Resolver::dumpTaskList(const PoolItemList &install, const PoolItemList &remove )
296 for (PoolItemList::const_iterator iter = install.begin();
297 iter != install.end(); iter++) {
298 DBG << " to_install " << *iter << endl;
300 for (PoolItemList::const_iterator iter = remove.begin();
301 iter != remove.end(); iter++) {
302 DBG << " to_remove " << *iter << endl;
307 //---------------------------------------------------------------------------
310 Resolver::addSubscribedSource (Repository repo)
312 _subscribed.insert(repo);
316 Resolver::addPoolItemToInstall (PoolItem_Ref item)
319 for (PoolItemList::const_iterator iter = _items_to_remove.begin();
320 iter != _items_to_remove.end(); iter++) {
322 _items_to_remove.remove(*iter);
328 _items_to_install.push_back (item);
329 _items_to_install.unique ();
335 Resolver::addPoolItemsToInstallFromList (PoolItemList & rl)
337 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
338 addPoolItemToInstall (*iter);
344 Resolver::addPoolItemToRemove (PoolItem_Ref item)
347 for (PoolItemList::const_iterator iter = _items_to_install.begin();
348 iter != _items_to_install.end(); iter++) {
350 _items_to_install.remove(*iter);
356 _items_to_remove.push_back (item);
357 _items_to_remove.unique ();
363 Resolver::addPoolItemsToRemoveFromList (PoolItemList & rl)
365 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
366 addPoolItemToRemove (*iter);
371 Resolver::addPoolItemToLockUninstalled (PoolItem_Ref item)
373 _items_to_lockUninstalled.push_back (item);
374 _items_to_lockUninstalled.unique ();
379 Resolver::addPoolItemToEstablish (PoolItem_Ref item)
381 _items_to_establish.push_back (item);
386 Resolver::addPoolItemsToEstablishFromList (PoolItemList & rl)
388 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
389 addPoolItemToEstablish (*iter);
395 Resolver::addPoolItemToVerify (PoolItem_Ref item)
398 /** Order PoolItems based on name and edition only. */
400 /** 'less then' based on name and edition */
401 bool operator()( PoolItem_Ref lhs, PoolItem_Ref rhs ) const
403 int res = lhs->name().compare( rhs->name() );
405 return res == -1; // lhs < rhs ?
406 // here: lhs == rhs, so compare edition:
407 return lhs->edition() < rhs->edition();
412 _items_to_verify.push_back (item);
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);
420 Resolver::addExtraCapability (const Capability & capability)
422 _extra_caps.insert (capability);
427 Resolver::addExtraConflict (const Capability & capability)
429 _extra_conflicts.insert (capability);
434 Resolver::addIgnoreConflict (const PoolItem_Ref item,
435 const Capability & capability)
437 _ignoreConflicts.insert(make_pair(item, capability));
442 Resolver::addIgnoreRequires (const PoolItem_Ref item,
443 const Capability & capability)
445 _ignoreRequires.insert(make_pair(item, capability));
449 Resolver::addIgnoreObsoletes (const PoolItem_Ref item,
450 const Capability & capability)
452 _ignoreObsoletes.insert(make_pair(item, capability));
456 Resolver::addIgnoreInstalledItem (const PoolItem_Ref item)
458 _ignoreInstalledItem.push_back (item);
462 Resolver::addIgnoreArchitectureItem (const PoolItem_Ref item)
464 _ignoreArchitectureItem.push_back (item);
468 Resolver::addIgnoreVendorItem (const PoolItem_Ref item)
470 _ignoreVendorItem.push_back (item);
473 //---------------------------------------------------------------------------
475 struct UndoTransact : public resfilter::PoolItemFilterFunctor
477 ResStatus::TransactByValue resStatus;
478 UndoTransact ( const ResStatus::TransactByValue &status)
482 bool operator()( PoolItem_Ref item ) // only transacts() items go here
484 item.status().resetTransact( resStatus );// clear any solver/establish transactions
490 struct DoTransact : public resfilter::PoolItemFilterFunctor
492 ResStatus::TransactByValue resStatus;
493 DoTransact ( const ResStatus::TransactByValue &status)
497 bool operator()( PoolItem_Ref item ) // only transacts() items go here
499 item.status().setTransact( true, resStatus );
505 struct VerifySystem : public resfilter::PoolItemFilterFunctor
509 VerifySystem (Resolver & r)
513 bool operator()( PoolItem_Ref provider )
515 resolver.addPoolItemToVerify (provider);
521 Resolver::verifySystem (bool considerNewHardware)
523 UndoTransact resetting (ResStatus::APPL_HIGH);
525 _DEBUG ("Resolver::verifySystem() " << (considerNewHardware ? "consider new hardware":""));
527 invokeOnEach ( _pool.begin(), _pool.end(),
528 resfilter::ByTransact( ), // Resetting all transcations
529 functor::functorRef<bool,PoolItem>(resetting) );
531 VerifySystem info (*this);
533 invokeOnEach( pool().byKindBegin( ResTraits<Package>::kind ),
534 pool().byKindEnd( ResTraits<Package>::kind ),
535 resfilter::ByInstalled ( ),
536 functor::functorRef<bool,PoolItem>(info) );
538 invokeOnEach( pool().byKindBegin( ResTraits<Pattern>::kind ),
539 pool().byKindEnd( ResTraits<Pattern>::kind ),
540 resfilter::ByInstalled ( ),
541 functor::functorRef<bool,PoolItem>(info) );
546 bool success = false;
548 if (considerNewHardware) {
549 // evaluate all Freshens/Supplements and solve
550 success = freshenPool(false) && bestContext() && bestContext()->isValid();
553 success = resolveDependencies (); // do solve only
556 DoTransact setting (ResStatus::APPL_HIGH);
558 invokeOnEach ( _pool.begin(), _pool.end(),
559 resfilter::ByTransact( ),
560 functor::functorRef<bool,PoolItem>(setting) );
566 //---------------------------------------------------------------------------
568 // copy marked item from solution back to pool
569 // if data != NULL, set as APPL_LOW (from establishPool())
572 solution_to_pool (PoolItem_Ref item, const ResStatus & status, void *data)
574 if (triggeredSolution.find(item) != triggeredSolution.end()) {
575 _XDEBUG("solution_to_pool(" << item << ") is already in the pool --> skip");
579 triggeredSolution.insert(item);
581 // resetting transaction only
582 item.status().resetTransact((data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
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);
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);
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);
598 else if (status.isIncomplete()
599 || status.isNeeded()) {
600 r = item.status().setIncomplete();
601 _XDEBUG("solution_to_pool(" << item << ", " << status << ") incomplete !" << r);
603 else if (status.isUnneeded()) {
604 r = item.status().setUnneeded();
605 _XDEBUG("solution_to_pool(" << item << ", " << status << ") unneeded !" << r);
607 else if (status.isSatisfied()) {
608 r = item.status().setSatisfied();
609 _XDEBUG("solution_to_pool(" << item << ", " << status << ") satisfied !" << r);
611 _XDEBUG("solution_to_pool(" << item << ", " << status << ") unchanged !");
617 //---------------------------------------------------------------------------
620 struct EstablishState
624 EstablishState (Resolver & r)
628 bool operator()( PoolItem_Ref provider )
630 resolver.addPoolItemToEstablish (provider);
637 Resolver::establishState( ResolverContext_Ptr context )
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);
652 context = new ResolverContext(_pool, _architecture);
654 context->setEstablishing (true);
655 context->setIgnoreCababilities (_ignoreConflicts,
658 _ignoreInstalledItem,
659 _ignoreArchitectureItem,
661 context->setForceResolve( _forceResolve );
662 context->setEstablishContext( _establish_context );
663 context->setPreferHighestVersion ( _preferHighestVersion );
664 context->setUpgradeMode( _upgradeMode );
666 for (KindList::const_iterator iter = ordered.begin(); iter != ordered.end(); iter++) {
667 const Resolvable::Kind kind = *iter;
669 _XDEBUG( "establishing state for kind " << kind.asString() );
671 //world()->foreachResItemByKind (kind, trial_establish_cb, this);
673 EstablishState info (*this);
675 invokeOnEach( pool().byKindBegin( kind ),
676 pool().byKindEnd( kind ),
677 functor::functorRef<bool,PoolItem>(info) );
680 resolveDependencies( context );
681 reset( false, true ); //resetValidResults,keepExtras
684 context->setEstablishing (false);
686 _best_context = context;
687 _establish_context = context;
694 Resolver::establishPool ()
696 MIL << "Resolver::establishPool()" << endl;
698 establishState (); // establish !
699 ResolverContext_Ptr solution = bestContext();
701 if (solution) { // copy solution back to pool
702 triggeredSolution.clear();
703 solution->foreachMarked (solution_to_pool, (void *)1); // as APPL_LOW
706 ERR << "establishState did not return a bestContext" << endl;
714 //---------------------------------------------------------------------------
717 typedef map<string, PoolItem_Ref> FreshenMap;
719 // add item to itemmap
720 // check for item with same name and only keep
721 // best architecture, best version
724 addToFreshen( PoolItem_Ref item, FreshenMap & itemmap )
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
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
739 itemmap[item->name()] = item;
752 bool operator()( PoolItem_Ref item)
754 CapSet freshens( item->dep( Dep::FRESHENS ) );
755 if (!freshens.empty()) {
756 addToFreshen( item, itemmap );
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 );
772 Resolver::freshenState( ResolverContext_Ptr context,
773 bool resetAfterSolve )
775 _DEBUG( "Resolver::freshenState ()" );
778 context = new ResolverContext( _pool, _architecture );
780 context->setEstablishing( true );
781 context->setIgnoreCababilities( _ignoreConflicts,
784 _ignoreInstalledItem,
785 _ignoreArchitectureItem,
787 context->setForceResolve( _forceResolve );
788 context->setEstablishContext( _establish_context );
789 context->setPreferHighestVersion( _preferHighestVersion );
790 context->setUpgradeMode( _upgradeMode );
794 // collect items to be established
796 invokeOnEach( pool().byKindBegin( ResTraits<zypp::Package>::kind ),
797 pool().byKindEnd( ResTraits<zypp::Package>::kind ),
798 functor::functorRef<bool,PoolItem>(info) );
800 // schedule all collected items for establish
802 for (FreshenMap::iterator it = info.itemmap.begin(); it != info.itemmap.end(); ++it) {
803 addPoolItemToEstablish( it->second );
807 resolveDependencies( context );
809 if (resetAfterSolve) {
810 reset( false, true ); //resetValidResults,keepExtras
811 context->setEstablishing( false );
812 _best_context = context;
820 Resolver::freshenPool (bool resetAfterSolve)
822 MIL << "Resolver::freshenPool()" << endl;
824 freshenState (NULL, resetAfterSolve); // establish all packages with freshens; (NULL)= no initial context
825 ResolverContext_Ptr solution = bestContext();
827 if (solution) { // copy solution back to pool
828 triggeredSolution.clear();
829 solution->foreachMarked (solution_to_pool, (void *)1); // as APPL_LOW
832 ERR << "freshenState did not return a bestContext" << endl;
839 //---------------------------------------------------------------------------
841 struct FileSystemEstablishItem
845 FileSystemEstablishItem (Resolver & r)
849 // items with filecaps has to be evaluate again via establish
851 bool operator()( const CapAndItem & cai )
853 _XDEBUG( "QueueItemInstall::FileSystemEstablishItem (" << cai.item << ", " << cai.cap << ")");
854 resolver.addPoolItemToEstablish (cai.item);
862 Resolver::resolveDependencies (const ResolverContext_Ptr context)
865 time_t t_start, t_now;
867 MIL << "Resolver::resolveDependencies()" << endl;
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;
877 #warning local items disabled
879 bool have_local_items = false;
881 /* Walk through are list of to-be-installed packages and see if any of them are local. */
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;
890 World_Ptr the_world = world();
891 StoreWorld_Ptr local_world = NULL;
892 MultiWorld_Ptr local_multiworld = NULL;
894 Channel_Ptr local_channel = NULL;
896 if (have_local_items) {
897 local_multiworld = new MultiWorld();
898 local_world = new StoreWorld();
900 local_channel = new Channel ("", "Local ResItems", "@local", "");
902 local_world->addChannel (local_channel);
904 local_multiworld->addSubworld (local_world);
905 local_multiworld->addSubworld (the_world);
907 the_world = local_multiworld;
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 ) );
918 // create initial_queue
920 ResolverQueue_Ptr initial_queue = new ResolverQueue(_pool, _architecture, context);
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));
933 // Initialize all ignoring dependencies
934 initial_queue->context()->setIgnoreCababilities (_ignoreConflicts,
937 _ignoreInstalledItem,
938 _ignoreArchitectureItem,
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 );
946 /* If this is a verify, we do a "soft resolution" */
948 initial_queue->context()->setVerifying( _verifying );
950 /* Add extra items. */
952 for (QueueItemList::const_iterator iter = _initial_items.begin(); iter != _initial_items.end(); iter++) {
953 initial_queue->addItem (*iter);
956 for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
957 PoolItem_Ref r = *iter;
959 #warning local items disabled
961 /* Add local packages to our dummy channel. */
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);
969 initial_queue->addPoolItemToInstall (r);
972 for (PoolItemList::const_iterator iter = _items_to_remove.begin(); iter != _items_to_remove.end(); iter++) {
974 initial_queue->addPoolItemToRemove (*iter, true /* remove-only mode */);
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 */);
984 for (PoolItemList::const_iterator iter = _items_to_verify.begin(); iter != _items_to_verify.end(); iter++) {
985 initial_queue->addPoolItemToVerify (*iter);
988 for (PoolItemList::const_iterator iter = _items_to_establish.begin(); iter != _items_to_establish.end(); iter++) {
989 initial_queue->addPoolItemToEstablish (*iter);
992 for (CapSet::const_iterator iter = _extra_caps.begin(); iter != _extra_caps.end(); iter++) {
993 initial_queue->addExtraCapability (*iter);
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);
1006 for (CapSet::const_iterator iter = _extra_conflicts.begin(); iter != _extra_conflicts.end(); iter++) {
1007 initial_queue->addExtraConflict (*iter);
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);
1020 // Adding System resolvable
1021 assertSystemResObjectInPool();
1023 _XDEBUG( "Initial Queue: [" << *initial_queue << "]" );
1025 if (initial_queue->isEmpty()) {
1026 INT << "Empty Queue, nothing to resolve" << endl;
1027 _best_context = context; // Taking old context
1031 _best_context = NULL;
1033 _pending_queues.push_front (initial_queue);
1037 while (!_pending_queues.empty()) {
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() );
1045 if (_timeout_seconds > 0) {
1047 if (difftime (t_now, t_start) > _timeout_seconds) {
1049 MIL << "Timeout " << _timeout_seconds << " seconds reached"
1050 << " -> exit" << endl;
1054 if (_maxSolverPasses > 0) {
1055 if (_maxSolverPasses <= _complete_queues.size() +
1056 _pruned_queues.size() +
1057 _deferred_queues.size() +
1058 _invalid_queues.size()) {
1060 MIL << "Max solver runs ( " << _maxSolverPasses
1061 << " ) reached -> exit" << endl;
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;
1073 ResolverQueue_Ptr queue = _pending_queues.front();
1074 _pending_queues.pop_front();
1075 ResolverContext_Ptr context = queue->context();
1079 if (queue->isInvalid ()) {
1081 _XDEBUG( "Invalid Queue\n" );
1082 _invalid_queues.push_back(queue);
1084 } else if (queue->isEmpty ()) {
1086 _XDEBUG( "Empty Queue\n" );
1088 _complete_queues.push_back(queue);
1090 ++_valid_solution_count;
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. */
1096 if (_best_context == NULL
1097 || _best_context->compare (context) < 0)
1099 _best_context = context;
1102 } else if (_best_context != NULL
1103 && _best_context->partialCompare (context) > 0) {
1105 /* If we aren't currently as good as our previous best complete solution,
1106 this solution gets pruned. */
1108 _XDEBUG( "PRUNED!" );
1110 _pruned_queues.push_back(queue);
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. */
1117 queue->splitFirstBranch (_pending_queues, _deferred_queues);
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
1124 if (_pending_queues.empty()
1125 && _complete_queues.empty()
1126 && !_deferred_queues.empty()) {
1127 _pending_queues.push_back(_deferred_queues.front());
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() );
1136 return _best_context && _best_context->isValid();
1140 //----------------------------------------------------------------------------
1144 Resolver::undo(void)
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();
1170 //----------------------------------------------------------------------------
1173 struct CollectTransact : public resfilter::PoolItemFilterFunctor
1175 Resolver & resolver;
1177 CollectTransact (Resolver & r)
1181 bool operator()( PoolItem_Ref item ) // only transacts() items go here
1183 ResStatus status = item.status();
1184 _XDEBUG( "CollectTransact(" << item << ")" );
1185 bool by_solver = (status.isBySolver() || status.isByApplLow());
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
1193 if (status.isToBeInstalled()) {
1194 resolver.addPoolItemToInstall(item); // -> install!
1196 if (status.isToBeUninstalled()) {
1197 resolver.addPoolItemToRemove(item); // -> remove !
1199 if (status.isIncomplete()) { // incomplete (re-install needed)
1200 PoolItem_Ref reinstall = Helper::findReinstallItem (resolver.pool(), item);
1202 MIL << "Reinstall " << reinstall << " for incomplete " << item << endl;
1203 resolver.addPoolItemToInstall(reinstall); // -> install!
1206 WAR << "Can't find " << item << " for re-installation" << endl;
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);
1223 show_pool( ResPool pool )
1226 static bool full_pool_shown = true;
1228 _XDEBUG( "---------------------------------------" );
1229 for (ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it, ++count) {
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
1235 _DEBUG( count << ": " << *it );
1238 _XDEBUG( "---------------------------------------" );
1239 full_pool_shown = true;
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
1246 // Every toBeInstalled is passed to zypp::solver:detail::Resolver.addPoolItemToInstall()
1247 // Every toBeUninstalled is passed to zypp::solver:detail::Resolver.addPoolItemToRemove()
1249 // Then zypp::solver:detail::Resolver.resolveDependencies() is called.
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.
1254 // ResolverContext has a foreachMarked() iterator function which loops over all
1255 // items of the solutions. These must be written back to the pool.
1259 Resolver::resolvePool( bool tryAllPossibilities )
1261 ResolverContext_Ptr saveContext = _best_context;
1262 CollectTransact info (*this);
1264 // cleanup before next run
1265 if ( _poolchanged.remember( _pool.serial() ) )
1267 MIL << "pool has been CHANGED --> resetting solverresults" << endl;
1268 reset( true, true ); //resetValidResults,keepExtras
1270 reset( false, true ); //resetValidResults,keepExtras
1273 bool saveTryAllPossibilities = _tryAllPossibilities;
1275 if (tryAllPossibilities) {
1276 _tryAllPossibilities = tryAllPossibilities;
1279 if (_tryAllPossibilities) {
1280 MIL << "================================================================"
1282 MIL << "Solver run with ALL possibilities"
1284 if (_maxSolverPasses <= 0)
1285 _maxSolverPasses = MAX_SECOND_RUNS;
1286 if (_timeout_seconds <= 0)
1287 _timeout_seconds = TIMOUT_SECOND_RUN;
1289 MIL << "But no longer than " << MAX_SECOND_RUNS << " runs or "
1290 << TIMOUT_SECOND_RUN << " seconds" << endl;
1291 MIL << "================================================================" << endl;
1296 MIL << "Resolver::resolvePool()" << endl;
1297 _XDEBUG( "Pool before resolve" );
1301 invokeOnEach ( _pool.begin(), _pool.end(),
1302 resfilter::ByTransact( ), // collect transacts from Pool to resolver queue
1303 functor::functorRef<bool,PoolItem>(info) );
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;
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
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 );
1326 bool have_solution = resolveDependencies (saveContext); // resolve !
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);
1334 _XDEBUG( "Pool after resolve" );
1337 // insert best_context in ContextPool for further solver runs
1338 contextPool.addContext( solution,_completeItems_to_install, _completeItems_to_remove, _completeItems_to_lockUninstalled);
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;
1346 for (ResolverQueueList::iterator iter = _invalid_queues.begin();
1347 iter != _invalid_queues.end(); iter++) {
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;
1359 if (tryAllPossibilities) {
1360 _tryAllPossibilities = saveTryAllPossibilities; // reset to old value
1363 return have_solution;
1368 get_info_foreach_cb (ResolverInfo_Ptr info, void *data)
1370 list<string> *stringList = (list<string> *)data;
1371 stringList->push_back (info->message());
1375 // returns a string list of ResolverInfo of the LAST not valid solution
1376 std::list<std::string> Resolver::problemDescription( void ) const
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);;
1387 // transact a single object
1388 // -> do a 'single step' resolving either installing or removing
1389 // required and recommended PoolItems
1392 Resolver::transactResObject( ResObject::constPtr robj, bool install,
1395 MIL << "transactResObject()" << endl;
1396 MIL << "is obsolete; use resolvePool() instead" << endl;
1403 Resolver::transactResKind( Resolvable::Kind kind )
1405 MIL << "transactResKind(" << kind << ")" << endl;
1406 MIL << "is obsolete; use resolvePool() instead" << endl;
1413 Resolver::transactReset( ResStatus::TransactByValue causer )
1415 MIL << "transactReset(" << causer << ")" << endl;
1416 MIL << "is obsolete; use resolvePool() instead" << endl;
1421 ///////////////////////////////////////////////////////////////////
1422 };// namespace detail
1423 /////////////////////////////////////////////////////////////////////
1424 /////////////////////////////////////////////////////////////////////
1425 };// namespace solver
1426 ///////////////////////////////////////////////////////////////////////
1427 ///////////////////////////////////////////////////////////////////////
1429 /////////////////////////////////////////////////////////////////////////