00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "zypp/solver/detail/Resolver.h"
00023 #include "zypp/solver/detail/Helper.h"
00024
00025 #include "zypp/CapSet.h"
00026 #include "zypp/base/Logger.h"
00027 #include "zypp/base/String.h"
00028 #include "zypp/base/Gettext.h"
00029
00030 #include "zypp/base/Algorithm.h"
00031 #include "zypp/ResPool.h"
00032 #include "zypp/ResFilters.h"
00033 #include "zypp/CapFilters.h"
00034 #include "zypp/ZYppFactory.h"
00035 #include "zypp/SystemResObject.h"
00036
00037
00039 namespace zypp
00040 {
00041
00042 namespace zypp_detail
00043 {
00044 Arch defaultArchitecture();
00046 }
00048
00050 namespace solver
00051 {
00052
00053 namespace detail
00054 {
00055
00056 using namespace std;
00057
00058 IMPL_PTR_TYPE(Resolver);
00059
00060 static const unsigned MAX_SECOND_RUNS( 3 );
00061 static const unsigned MAX_VALID_SOLUTIONS( 50 );
00062 static const unsigned TIMOUT_SECOND_RUN( 30 );
00063
00064
00065
00066 std::ostream &
00067 Resolver::dumpOn( std::ostream & os ) const
00068 {
00069 return os << "<resolver/>";
00070 }
00071
00072
00073
00074 void assertSystemResObjectInPool()
00075 {
00076 ResPool pool( getZYpp()->pool() );
00077 if ( pool.byKindBegin<SystemResObject>()
00078 == pool.byKindEnd<SystemResObject>() )
00079 {
00080
00081 ResStore store;
00082 store.insert( SystemResObject::instance() );
00083 getZYpp()->addResolvables( store, true );
00084 }
00085
00086
00087 if ( ! pool.byKindBegin<SystemResObject>()
00088 ->status().setLock( true, ResStatus::USER ) )
00089 {
00090 WAR << "Unable to set SystemResObject to lock" << endl;
00091 }
00092 }
00093
00094
00095
00096 Resolver::Resolver (const ResPool & pool)
00097 : _pool (pool)
00098 , _timeout_seconds (0)
00099 , _maxSolverPasses (0)
00100 , _verifying (false)
00101 , _testing (false)
00102 , _tryAllPossibilities (false)
00103 , _skippedPossibilities (false)
00104 , _valid_solution_count (0)
00105 , _best_context (NULL)
00106 , _establish_context (NULL)
00107 , _timed_out (false)
00108 , _architecture( zypp_detail::defaultArchitecture() )
00109 , _forceResolve (false)
00110 , _upgradeMode (false)
00111 , _preferHighestVersion (true)
00112
00113 {}
00114
00115
00116 Resolver::~Resolver()
00117 {
00118 }
00119
00120
00121
00122 ResPool
00123 Resolver::pool (void) const
00124 {
00125 return _pool;
00126 }
00127
00128 void
00129 Resolver::reset (void)
00130 {
00131 _verifying = false;
00132
00133 _initial_items.clear();
00134
00135 _items_to_install.clear();
00136 _items_to_remove.clear();
00137 _items_to_verify.clear();
00138 _items_to_establish.clear();
00139
00140 _extra_caps.clear();
00141 _extra_conflicts.clear();
00142
00143 _pending_queues.clear();
00144 _pruned_queues.clear();
00145 _complete_queues.clear();
00146 _deferred_queues.clear();
00147 _invalid_queues.clear();
00148
00149 _valid_solution_count = 0;
00150
00151 _best_context = NULL;
00152 _timed_out = false;
00153
00154 _tryAllPossibilities = false;
00155 _skippedPossibilities = false;
00156
00157 }
00158
00159
00160 ResolverContext_Ptr
00161 Resolver::context (void) const
00162 {
00163 if (_best_context) return _best_context;
00164 if (_invalid_queues.empty()) return NULL;
00165 ResolverQueue_Ptr invalid = _invalid_queues.front();
00166 return invalid->context();
00167 }
00168
00169
00170
00171 void
00172 Resolver::addSubscribedSource (Source_Ref source)
00173 {
00174 _subscribed.insert(source);
00175 }
00176
00177 void
00178 Resolver::addPoolItemToInstall (PoolItem_Ref item)
00179 {
00180 bool found = false;
00181 for (PoolItemList::const_iterator iter = _items_to_remove.begin();
00182 iter != _items_to_remove.end(); iter++) {
00183 if (*iter == item) {
00184 _items_to_remove.remove(*iter);
00185 found = true;
00186 break;
00187 }
00188 }
00189 if (!found)
00190 _items_to_install.push_back (item);
00191 }
00192
00193
00194 void
00195 Resolver::addPoolItemsToInstallFromList (PoolItemList & rl)
00196 {
00197 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00198 addPoolItemToInstall (*iter);
00199 }
00200 }
00201
00202
00203 void
00204 Resolver::addPoolItemToRemove (PoolItem_Ref item)
00205 {
00206 bool found = false;
00207 for (PoolItemList::const_iterator iter = _items_to_install.begin();
00208 iter != _items_to_install.end(); iter++) {
00209 if (*iter == item) {
00210 _items_to_install.remove(*iter);
00211 found = true;
00212 break;
00213 }
00214 }
00215 if (!found)
00216 _items_to_remove.push_back (item);
00217 }
00218
00219
00220 void
00221 Resolver::addPoolItemsToRemoveFromList (PoolItemList & rl)
00222 {
00223 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00224 addPoolItemToRemove (*iter);
00225 }
00226 }
00227
00228
00229 void
00230 Resolver::addPoolItemToEstablish (PoolItem_Ref item)
00231 {
00232 _items_to_establish.push_back (item);
00233 }
00234
00235
00236 void
00237 Resolver::addPoolItemsToEstablishFromList (PoolItemList & rl)
00238 {
00239 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00240 addPoolItemToEstablish (*iter);
00241 }
00242 }
00243
00244
00245 void
00246 Resolver::addPoolItemToVerify (PoolItem_Ref item)
00247 {
00248 #if 0
00249
00250 struct {
00252 bool operator()( PoolItem_Ref lhs, PoolItem_Ref rhs ) const
00253 {
00254 int res = lhs->name().compare( rhs->name() );
00255 if ( res )
00256 return res == -1;
00257
00258 return lhs->edition() < rhs->edition();
00259 }
00260 } order;
00261 #endif
00262
00263 _items_to_verify.push_back (item);
00264
00265 #warning Should order by name (and probably edition since with zypp we could have multiple editions installed in parallel)
00266
00267 }
00268
00269
00270 void
00271 Resolver::addExtraCapability (const Capability & capability)
00272 {
00273 _extra_caps.insert (capability);
00274 }
00275
00276
00277 void
00278 Resolver::addExtraConflict (const Capability & capability)
00279 {
00280 _extra_conflicts.insert (capability);
00281 }
00282
00283
00284 void
00285 Resolver::addIgnoreConflict (const PoolItem_Ref item,
00286 const Capability & capability)
00287 {
00288 _ignoreConflicts.insert(make_pair(item, capability));
00289 }
00290
00291
00292 void
00293 Resolver::addIgnoreRequires (const PoolItem_Ref item,
00294 const Capability & capability)
00295 {
00296 _ignoreRequires.insert(make_pair(item, capability));
00297 }
00298
00299 void
00300 Resolver::addIgnoreObsoletes (const PoolItem_Ref item,
00301 const Capability & capability)
00302 {
00303 _ignoreObsoletes.insert(make_pair(item, capability));
00304 }
00305
00306 void
00307 Resolver::addIgnoreInstalledItem (const PoolItem_Ref item)
00308 {
00309 _ignoreInstalledItem.push_back (item);
00310 }
00311
00312 void
00313 Resolver::addIgnoreArchitectureItem (const PoolItem_Ref item)
00314 {
00315 _ignoreArchitectureItem.push_back (item);
00316 }
00317
00318
00319
00320
00321 struct UndoTransact : public resfilter::PoolItemFilterFunctor
00322 {
00323 ResStatus::TransactByValue resStatus;
00324 UndoTransact ( const ResStatus::TransactByValue &status)
00325 :resStatus(status)
00326 { }
00327
00328 bool operator()( PoolItem_Ref item )
00329 {
00330 item.status().resetTransact( resStatus );
00331 return true;
00332 }
00333 };
00334
00335
00336 struct DoTransact : public resfilter::PoolItemFilterFunctor
00337 {
00338 ResStatus::TransactByValue resStatus;
00339 DoTransact ( const ResStatus::TransactByValue &status)
00340 :resStatus(status)
00341 { }
00342
00343 bool operator()( PoolItem_Ref item )
00344 {
00345 item.status().setTransact( true, resStatus );
00346 return true;
00347 }
00348 };
00349
00350
00351 struct VerifySystem : public resfilter::PoolItemFilterFunctor
00352 {
00353 Resolver & resolver;
00354
00355 VerifySystem (Resolver & r)
00356 : resolver (r)
00357 { }
00358
00359 bool operator()( PoolItem_Ref provider )
00360 {
00361 resolver.addPoolItemToVerify (provider);
00362 return true;
00363 }
00364 };
00365
00366 bool
00367 Resolver::verifySystem (bool considerNewHardware)
00368 {
00369 UndoTransact resetting (ResStatus::APPL_HIGH);
00370
00371 _DEBUG ("Resolver::verifySystem() " << (considerNewHardware ? "consider new hardware":""));
00372
00373 invokeOnEach ( _pool.begin(), _pool.end(),
00374 resfilter::ByTransact( ),
00375 functor::functorRef<bool,PoolItem>(resetting) );
00376
00377 VerifySystem info (*this);
00378
00379 invokeOnEach( pool().byKindBegin( ResTraits<Package>::kind ),
00380 pool().byKindEnd( ResTraits<Package>::kind ),
00381 resfilter::ByInstalled ( ),
00382 functor::functorRef<bool,PoolItem>(info) );
00383
00384 invokeOnEach( pool().byKindBegin( ResTraits<Pattern>::kind ),
00385 pool().byKindEnd( ResTraits<Pattern>::kind ),
00386 resfilter::ByInstalled ( ),
00387 functor::functorRef<bool,PoolItem>(info) );
00388
00389
00390 _verifying = true;
00391
00392 bool success = false;
00393
00394 if (considerNewHardware) {
00395
00396 success = freshenPool(false) && bestContext() && bestContext()->isValid();
00397 }
00398 else {
00399 success = resolveDependencies ();
00400 }
00401
00402 DoTransact setting (ResStatus::APPL_HIGH);
00403
00404 invokeOnEach ( _pool.begin(), _pool.end(),
00405 resfilter::ByTransact( ),
00406 functor::functorRef<bool,PoolItem>(setting) );
00407
00408 return success;
00409 }
00410
00411
00412
00413
00414
00415
00416
00417 static void
00418 solution_to_pool (PoolItem_Ref item, const ResStatus & status, void *data)
00419 {
00420 bool r;
00421
00422 if (status.isToBeInstalled()) {
00423 r = item.status().setToBeInstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00424 _XDEBUG("solution_to_pool(" << item << ", " << status << ") install !" << r);
00425 }
00426 else if (status.isToBeUninstalledDueToUpgrade()) {
00427 r = item.status().setToBeUninstalledDueToUpgrade( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00428 _XDEBUG("solution_to_pool(" << item << ", " << status << ") upgrade !" << r);
00429 }
00430 else if (status.isToBeUninstalled()) {
00431 r = item.status().setToBeUninstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00432 _XDEBUG("solution_to_pool(" << item << ", " << status << ") remove !" << r);
00433 }
00434 else if (status.isIncomplete()
00435 || status.isNeeded()) {
00436 r = item.status().setIncomplete();
00437 _XDEBUG("solution_to_pool(" << item << ", " << status << ") incomplete !" << r);
00438 }
00439 else if (status.isUnneeded()) {
00440 r = item.status().setUnneeded();
00441 _XDEBUG("solution_to_pool(" << item << ", " << status << ") unneeded !" << r);
00442 }
00443 else if (status.isSatisfied()) {
00444 r = item.status().setSatisfied();
00445 _XDEBUG("solution_to_pool(" << item << ", " << status << ") satisfied !" << r);
00446 } else {
00447 _XDEBUG("solution_to_pool(" << item << ", " << status << ") unchanged !");
00448 }
00449 return;
00450 }
00451
00452
00453
00454
00455
00456 struct EstablishState
00457 {
00458 Resolver & resolver;
00459
00460 EstablishState (Resolver & r)
00461 : resolver (r)
00462 { }
00463
00464 bool operator()( PoolItem_Ref provider )
00465 {
00466 resolver.addPoolItemToEstablish (provider);
00467 return true;
00468 }
00469 };
00470
00471
00472 void
00473 Resolver::establishState( ResolverContext_Ptr context )
00474 {
00475 _DEBUG( "Resolver::establishState ()" );
00476 typedef list<Resolvable::Kind> KindList;
00477 static KindList ordered;
00478 if (ordered.empty()) {
00479 ordered.push_back (ResTraits<zypp::Atom>::kind);
00480 ordered.push_back (ResTraits<zypp::Message>::kind);
00481 ordered.push_back (ResTraits<zypp::Script>::kind);
00482 ordered.push_back (ResTraits<zypp::Patch>::kind);
00483 ordered.push_back (ResTraits<zypp::Pattern>::kind);
00484 ordered.push_back (ResTraits<zypp::Product>::kind);
00485 }
00486
00487 if (context == NULL)
00488 context = new ResolverContext(_pool, _architecture);
00489
00490 context->setEstablishing (true);
00491 context->setIgnoreCababilities (_ignoreConflicts,
00492 _ignoreRequires,
00493 _ignoreObsoletes,
00494 _ignoreInstalledItem,
00495 _ignoreArchitectureItem);
00496 context->setForceResolve( _forceResolve );
00497 context->setEstablishContext( _establish_context );
00498 context->setPreferHighestVersion ( _preferHighestVersion );
00499 context->setUpgradeMode( _upgradeMode );
00500
00501 for (KindList::const_iterator iter = ordered.begin(); iter != ordered.end(); iter++) {
00502 const Resolvable::Kind kind = *iter;
00503
00504 _XDEBUG( "establishing state for kind " << kind.asString() );
00505
00506
00507
00508 EstablishState info (*this);
00509
00510 invokeOnEach( pool().byKindBegin( kind ),
00511 pool().byKindEnd( kind ),
00512 functor::functorRef<bool,PoolItem>(info) );
00513
00514
00515 resolveDependencies( context );
00516
00517 reset();
00518 }
00519
00520 context->setEstablishing (false);
00521
00522 _best_context = context;
00523 _establish_context = context;
00524
00525 return;
00526 }
00527
00528
00529 bool
00530 Resolver::establishPool ()
00531 {
00532 MIL << "Resolver::establishPool()" << endl;
00533
00534 establishState ();
00535 ResolverContext_Ptr solution = bestContext();
00536
00537 if (solution) {
00538 solution->foreachMarked (solution_to_pool, (void *)1);
00539 }
00540 else {
00541 ERR << "establishState did not return a bestContext" << endl;
00542 return false;
00543 }
00544
00545 return true;
00546 }
00547
00548
00549
00550
00551
00552 typedef map<string, PoolItem_Ref> FreshenMap;
00553
00554
00555
00556
00557
00558 static void
00559 addToFreshen( PoolItem_Ref item, FreshenMap & itemmap )
00560 {
00561 FreshenMap::iterator it = itemmap.find( item->name() );
00562 if (it != itemmap.end()) {
00563 int cmp = it->second->arch().compare( item->arch() );
00564 if (cmp < 0) {
00565 it->second = item;
00566 }
00567 else if (cmp == 0) {
00568 if (it->second->edition().compare( item->edition() ) < 0) {
00569 it->second = item;
00570 }
00571 }
00572 }
00573 else {
00574 itemmap[item->name()] = item;
00575 }
00576 return;
00577 }
00578
00579
00580 struct FreshenState
00581 {
00582 FreshenMap itemmap;
00583
00584 FreshenState()
00585 { }
00586
00587 bool operator()( PoolItem_Ref item)
00588 {
00589 CapSet freshens( item->dep( Dep::FRESHENS ) );
00590 if (!freshens.empty()) {
00591 addToFreshen( item, itemmap );
00592 }
00593 else {
00594
00595
00596 CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
00597 if (!supplements.empty()) {
00598 addToFreshen( item, itemmap );
00599 }
00600 }
00601 return true;
00602 }
00603 };
00604
00605
00606 void
00607 Resolver::freshenState( ResolverContext_Ptr context,
00608 bool resetAfterSolve )
00609 {
00610 _DEBUG( "Resolver::freshenState ()" );
00611
00612 if (context == NULL)
00613 context = new ResolverContext( _pool, _architecture );
00614
00615 context->setEstablishing( true );
00616 context->setIgnoreCababilities( _ignoreConflicts,
00617 _ignoreRequires,
00618 _ignoreObsoletes,
00619 _ignoreInstalledItem,
00620 _ignoreArchitectureItem );
00621 context->setForceResolve( _forceResolve );
00622 context->setEstablishContext( _establish_context );
00623 context->setPreferHighestVersion( _preferHighestVersion );
00624 context->setUpgradeMode( _upgradeMode );
00625
00626 FreshenState info;
00627
00628
00629
00630 invokeOnEach( pool().byKindBegin( ResTraits<zypp::Package>::kind ),
00631 pool().byKindEnd( ResTraits<zypp::Package>::kind ),
00632 functor::functorRef<bool,PoolItem>(info) );
00633
00634
00635
00636 for (FreshenMap::iterator it = info.itemmap.begin(); it != info.itemmap.end(); ++it) {
00637 addPoolItemToEstablish( it->second );
00638 }
00639
00640
00641 resolveDependencies( context );
00642
00643 if (resetAfterSolve) {
00644 reset();
00645 context->setEstablishing( false );
00646 _best_context = context;
00647 }
00648
00649 return;
00650 }
00651
00652
00653 bool
00654 Resolver::freshenPool (bool resetAfterSolve)
00655 {
00656 MIL << "Resolver::freshenPool()" << endl;
00657
00658 freshenState (NULL, resetAfterSolve);
00659 ResolverContext_Ptr solution = bestContext();
00660
00661 if (solution) {
00662 solution->foreachMarked (solution_to_pool, (void *)1);
00663 }
00664 else {
00665 ERR << "freshenState did not return a bestContext" << endl;
00666 return false;
00667 }
00668
00669 return true;
00670 }
00671
00672
00673
00674 bool
00675 Resolver::resolveDependencies (const ResolverContext_Ptr context)
00676 {
00677
00678 time_t t_start, t_now;
00679
00680 MIL << "Resolver::resolveDependencies()" << endl;
00681
00682 _pending_queues.clear();
00683 _pruned_queues.clear();
00684 _complete_queues.clear();
00685 _deferred_queues.clear();
00686 _invalid_queues.clear();
00687 _valid_solution_count = 0;
00688 _best_context = NULL;
00689
00690 #warning local items disabled
00691 #if 0
00692 bool have_local_items = false;
00693
00694
00695
00696 for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00697 if ((*iter)->local()) {
00698 have_local_items = true;
00699 break;
00700 }
00701 }
00702
00703 World_Ptr the_world = world();
00704 StoreWorld_Ptr local_world = NULL;
00705 MultiWorld_Ptr local_multiworld = NULL;
00706
00707 Channel_Ptr local_channel = NULL;
00708
00709 if (have_local_items) {
00710 local_multiworld = new MultiWorld();
00711 local_world = new StoreWorld();
00712
00713 local_channel = new Channel ("", "Local ResItems", "@local", "");
00714
00715 local_world->addChannel (local_channel);
00716
00717 local_multiworld->addSubworld (local_world);
00718 local_multiworld->addSubworld (the_world);
00719
00720 the_world = local_multiworld;
00721 }
00722 #endif
00723
00724
00725
00726 ResolverQueue_Ptr initial_queue = new ResolverQueue(_pool, _architecture, context);
00727
00728
00729 IgnoreMap ignoreRequires = _ignoreRequires;
00730 ResPool::AdditionalCapSet additionalCapSet = pool().additionaProvide();
00731 for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
00732 it != additionalCapSet.end(); it++) {
00733 CapSet cset = it->second;
00734 for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
00735 ignoreRequires.insert(make_pair(PoolItem_Ref(), *cit));
00736 }
00737 }
00738
00739
00740 initial_queue->context()->setIgnoreCababilities (_ignoreConflicts,
00741 ignoreRequires,
00742 _ignoreObsoletes,
00743 _ignoreInstalledItem,
00744 _ignoreArchitectureItem);
00745 initial_queue->context()->setForceResolve( _forceResolve );
00746 initial_queue->context()->setEstablishContext( _establish_context );
00747 initial_queue->context()->setPreferHighestVersion( _preferHighestVersion );
00748 initial_queue->context()->setUpgradeMode( _upgradeMode );
00749 initial_queue->context()->setTryAllPossibilities( _tryAllPossibilities );
00750 initial_queue->context()->setScippedPossibilities( _skippedPossibilities );
00751
00752
00753
00754 initial_queue->context()->setVerifying( _verifying );
00755
00756
00757
00758 for (QueueItemList::const_iterator iter = _initial_items.begin(); iter != _initial_items.end(); iter++) {
00759 initial_queue->addItem (*iter);
00760 }
00761
00762 for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00763 PoolItem_Ref r = *iter;
00764
00765 #warning local items disabled
00766 #if 0
00767
00768 if (r->local()) {
00769 assert (local_channel != NULL);
00770 ResItem_Ptr r1 = const_pointer_cast<ResItem>(r);
00771 r1->setChannel (local_channel);
00772 local_world->addPoolItem_Ref (r);
00773 }
00774 #endif
00775 initial_queue->addPoolItemToInstall (r);
00776 }
00777
00778 for (PoolItemList::const_iterator iter = _items_to_remove.begin(); iter != _items_to_remove.end(); iter++) {
00779 if (!_upgradeMode)
00780 initial_queue->addPoolItemToRemove (*iter, true );
00781 else
00782
00783
00784
00785
00786
00787 initial_queue->addPoolItemToRemove (*iter, false );
00788 }
00789
00790 for (PoolItemList::const_iterator iter = _items_to_verify.begin(); iter != _items_to_verify.end(); iter++) {
00791 initial_queue->addPoolItemToVerify (*iter);
00792 }
00793
00794 for (PoolItemList::const_iterator iter = _items_to_establish.begin(); iter != _items_to_establish.end(); iter++) {
00795 initial_queue->addPoolItemToEstablish (*iter);
00796 }
00797
00798 for (CapSet::const_iterator iter = _extra_caps.begin(); iter != _extra_caps.end(); iter++) {
00799 initial_queue->addExtraCapability (*iter);
00800 }
00801
00802
00803 additionalCapSet = pool().additionalRequire();
00804 for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
00805 it != additionalCapSet.end(); it++) {
00806 CapSet cset = it->second;
00807 for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
00808 initial_queue->addExtraCapability (*cit);
00809 }
00810 }
00811
00812 for (CapSet::const_iterator iter = _extra_conflicts.begin(); iter != _extra_conflicts.end(); iter++) {
00813 initial_queue->addExtraConflict (*iter);
00814 }
00815
00816
00817 additionalCapSet = pool().additionaConflict();
00818 for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
00819 it != additionalCapSet.end(); it++) {
00820 CapSet cset = it->second;
00821 for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
00822 initial_queue->addExtraConflict (*cit);
00823 }
00824 }
00825
00826
00827 assertSystemResObjectInPool();
00828
00829 _XDEBUG( "Initial Queue: [" << *initial_queue << "]" );
00830
00831 if (initial_queue->isEmpty()) {
00832 INT << "Empty Queue, nothing to resolve" << endl;
00833
00834 return true;
00835 }
00836
00837 _best_context = NULL;
00838
00839 _pending_queues.push_front (initial_queue);
00840
00841 time (&t_start);
00842
00843 while (!_pending_queues.empty()) {
00844
00845 _DEBUG( "Pend " << (long) _pending_queues.size()
00846 << " / Cmpl " << (long) _complete_queues.size()
00847 << " / Prun " << (long) _pruned_queues.size()
00848 << " / Defr " << (long) _deferred_queues.size()
00849 << " / Invl " << (long) _invalid_queues.size() );
00850
00851 if (_timeout_seconds > 0) {
00852 time (&t_now);
00853 if (difftime (t_now, t_start) > _timeout_seconds) {
00854 _timed_out = true;
00855 MIL << "Timeout " << _timeout_seconds << " seconds reached"
00856 << " -> exit" << endl;
00857 break;
00858 }
00859 }
00860 if (_maxSolverPasses > 0) {
00861 if (_maxSolverPasses <= _complete_queues.size() +
00862 _pruned_queues.size() +
00863 _deferred_queues.size() +
00864 _invalid_queues.size()) {
00865 _timed_out = true;
00866 MIL << "Max solver runs ( " << _maxSolverPasses
00867 << " ) reached -> exit" << endl;
00868 break;
00869 }
00870 }
00871
00872 if (_best_context != NULL
00873 && _complete_queues.size() >= MAX_VALID_SOLUTIONS) {
00874 MIL << "Max VALID solver runs ( " << MAX_VALID_SOLUTIONS
00875 << " ) reached -> exit" << endl;
00876 break;
00877 }
00878
00879 ResolverQueue_Ptr queue = _pending_queues.front();
00880 _pending_queues.pop_front();
00881 ResolverContext_Ptr context = queue->context();
00882
00883 queue->process();
00884
00885 if (queue->isInvalid ()) {
00886
00887 _XDEBUG( "Invalid Queue\n" );
00888 _invalid_queues.push_back(queue);
00889
00890 } else if (queue->isEmpty ()) {
00891
00892 _XDEBUG( "Empty Queue\n" );
00893
00894 _complete_queues.push_back(queue);
00895
00896 ++_valid_solution_count;
00897
00898
00899
00900
00901
00902 if (_best_context == NULL
00903 || _best_context->compare (context) < 0)
00904 {
00905 _best_context = context;
00906 }
00907
00908 } else if (_best_context != NULL
00909 && _best_context->partialCompare (context) > 0) {
00910
00911
00912
00913
00914 _XDEBUG( "PRUNED!" );
00915
00916 _pruned_queues.push_back(queue);
00917
00918 } else {
00919
00920
00921
00922
00923 queue->splitFirstBranch (_pending_queues, _deferred_queues);
00924 }
00925
00926
00927
00928
00929
00930 if (_pending_queues.empty()
00931 && _complete_queues.empty()
00932 && !_deferred_queues.empty()) {
00933 _pending_queues.push_back(_deferred_queues.front());
00934 }
00935 }
00936 _DEBUG("Pend " << (long) _pending_queues.size()
00937 << " / Cmpl " << (long) _complete_queues.size()
00938 << " / Prun " << (long) _pruned_queues.size()
00939 << " / Defr " << (long) _deferred_queues.size()
00940 << " / Invl " << (long) _invalid_queues.size() );
00941
00942
00943 if ( !(_best_context && _best_context->isValid())
00944 && !_tryAllPossibilities ) {
00945
00946 for (ResolverQueueList::iterator iter = _invalid_queues.begin();
00947 iter != _invalid_queues.end(); iter++) {
00948
00949 ResolverQueue_Ptr invalid = *iter;
00950 if (invalid->context()->skippedPossibilities()) {
00951 _skippedPossibilities = true;
00952 break;
00953 }
00954 }
00955
00956 if (_skippedPossibilities) {
00957
00958 _tryAllPossibilities = true;
00959 MIL << "================================================================"
00960 << endl;
00961 MIL << "No valid solution, lets try a second run with ALL possibilities"
00962 << endl;
00963 if (_maxSolverPasses <= 0)
00964 _maxSolverPasses = MAX_SECOND_RUNS;
00965 if (_timeout_seconds <= 0)
00966 _timeout_seconds = TIMOUT_SECOND_RUN;
00967
00968 MIL << "But no longer than " << MAX_SECOND_RUNS << " runs or "
00969 << TIMOUT_SECOND_RUN << " seconds" << endl;
00970 MIL << "================================================================"
00971 << endl;
00972
00973 ResolverQueueList save_queues = _invalid_queues;
00974 resolveDependencies ();
00975 if (!(_best_context && _best_context->isValid()))
00976 _invalid_queues = save_queues;
00977 }
00978 }
00979
00980 return _best_context && _best_context->isValid();
00981 }
00982
00983
00984
00985
00986
00987
00988 void
00989 Resolver::undo(void)
00990 {
00991 UndoTransact info(ResStatus::APPL_LOW);
00992 MIL << "*** undo ***" << endl;
00993 invokeOnEach ( _pool.begin(), _pool.end(),
00994 resfilter::ByTransact( ),
00995 functor::functorRef<bool,PoolItem>(info) );
00996
00997 _ignoreConflicts.clear();
00998
00999 _ignoreRequires.clear();
01000
01001 _ignoreObsoletes.clear();
01002
01003 _ignoreArchitecture.clear();
01004
01005 _ignoreInstalledItem.clear();
01006
01007 _ignoreArchitectureItem.clear();
01008
01009
01010 return;
01011 }
01012
01013
01014
01015
01016 struct CollectTransact : public resfilter::PoolItemFilterFunctor
01017 {
01018 Resolver & resolver;
01019
01020 CollectTransact (Resolver & r)
01021 : resolver (r)
01022 { }
01023
01024 bool operator()( PoolItem_Ref item )
01025 {
01026 ResStatus status = item.status();
01027 _XDEBUG( "CollectTransact(" << item << ")" );
01028 bool by_solver = (status.isBySolver() || status.isByApplLow());
01029
01030 if (by_solver) {
01031 item.status().resetTransact( ResStatus::APPL_LOW );
01032 return true;
01033 }
01034
01035 if (status.isToBeInstalled()) {
01036 resolver.addPoolItemToInstall(item);
01037 }
01038 if (status.isToBeUninstalled()) {
01039 resolver.addPoolItemToRemove(item);
01040 }
01041 if (status.isIncomplete()) {
01042 PoolItem_Ref reinstall = Helper::findReinstallItem (resolver.pool(), item);
01043 if (reinstall) {
01044 MIL << "Reinstall " << reinstall << " for incomplete " << item << endl;
01045 resolver.addPoolItemToInstall(reinstall);
01046 }
01047 else {
01048 WAR << "Can't find " << item << " for re-installation" << endl;
01049 }
01050 }
01051 return true;
01052 }
01053 };
01054
01055
01056 static void
01057 show_pool( ResPool pool )
01058 {
01059 int count = 1;
01060 static bool full_pool_shown = true;
01061
01062 _XDEBUG( "---------------------------------------" );
01063 for (ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it, ++count) {
01064
01065 if (!full_pool_shown
01066 || it->status().transacts()
01067 || !it->status().isUndetermined())
01068 {
01069 _DEBUG( count << ": " << *it );
01070 }
01071 }
01072 _XDEBUG( "---------------------------------------" );
01073 full_pool_shown = true;
01074 }
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092 bool
01093 Resolver::resolvePool( bool tryAllPossibilities )
01094 {
01095 ResolverContext_Ptr context = NULL;
01096
01097 CollectTransact info (*this);
01098
01099
01100 reset();
01101
01102 if (tryAllPossibilities) {
01103 _tryAllPossibilities = tryAllPossibilities;
01104 context = new ResolverContext( _pool, _architecture );
01105 context->setTryAllPossibilities( true );
01106 }
01107
01108 #if 1
01109
01110 MIL << "Resolver::resolvePool()" << endl;
01111 _XDEBUG( "Pool before resolve" );
01112 show_pool( _pool );
01113
01114 #endif
01115 invokeOnEach ( _pool.begin(), _pool.end(),
01116 resfilter::ByTransact( ),
01117 functor::functorRef<bool,PoolItem>(info) );
01118
01119 bool have_solution = resolveDependencies( context );
01120
01121 if (have_solution) {
01122 MIL << "Have solution, copying back to pool" << endl;
01123 ResolverContext_Ptr solution = bestContext();
01124 solution->foreachMarked (solution_to_pool, NULL);
01125 #if 1
01126 _XDEBUG( "Pool after resolve" );
01127 show_pool( _pool );
01128 #endif
01129 }
01130 else {
01131 MIL << "!!! Have NO solution !!! Additional solver information:" << endl;
01132 int counter = 0;
01133 for (ResolverQueueList::iterator iter = _invalid_queues.begin();
01134 iter != _invalid_queues.end(); iter++) {
01135 counter++;
01136 MIL << "-----------------------------------------------------------------" << endl;
01137 MIL << counter++ << ". failed queue:" << endl;
01138 ResolverQueue_Ptr invalid = *iter;
01139 invalid->context()->spewInfo ();
01140 MIL << *invalid->context() << endl;
01141 MIL << "-----------------------------------------------------------------" << endl;
01142 }
01143 }
01144 return have_solution;
01145 }
01146
01147
01148 static void
01149 get_info_foreach_cb (ResolverInfo_Ptr info, void *data)
01150 {
01151 list<string> *stringList = (list<string> *)data;
01152 stringList->push_back (info->message());
01153 }
01154
01155
01156
01157 std::list<std::string> Resolver::problemDescription( void ) const
01158 {
01159 list<string> retList;
01160 if (_invalid_queues.empty()) return retList;
01161 ResolverQueue_Ptr invalid = _invalid_queues.front();
01162 invalid->context()->foreachInfo (PoolItem_Ref(), -1, get_info_foreach_cb, (void *)&retList);;
01163 return retList;
01164 }
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174 static bool
01175 transactItems( PoolItem_Ref installed, PoolItem_Ref uninstalled, bool install, bool soft, PoolItem_Ref & added )
01176 {
01177 if (install) {
01178 if (compareByNVRA (installed.resolvable(), uninstalled.resolvable()) != 0) {
01179 if (uninstalled
01180 && !uninstalled.status().isLocked())
01181 {
01182 bool adding;
01183 if (soft)
01184 adding = uninstalled.status().setSoftTransact( true, ResStatus::APPL_LOW );
01185 else
01186 adding = uninstalled.status().setTransact( true, ResStatus::APPL_LOW );
01187 if (adding)
01188 added = uninstalled;
01189 }
01190 if (installed
01191 && !installed.status().isLocked())
01192 {
01193 installed.status().resetTransact( ResStatus::APPL_LOW );
01194 }
01195 }
01196 } else {
01197
01198 if (uninstalled
01199 && !uninstalled.status().isLocked())
01200 {
01201 uninstalled.status().resetTransact( ResStatus::APPL_LOW );
01202 }
01203 if (installed
01204 && !installed.status().isLocked())
01205 {
01206 if (soft)
01207 installed.status().setSoftTransact( true, ResStatus::APPL_LOW );
01208 else
01209 installed.status().setTransact( true, ResStatus::APPL_LOW );
01210 }
01211 }
01212 if (!uninstalled
01213 && !installed)
01214 {
01215 return false;
01216 }
01217 return true;
01218 }
01219
01220
01221 typedef struct { PoolItem_Ref installed; PoolItem_Ref uninstalled; } IandU;
01222 typedef map<string, IandU> IandUMap;
01223
01224
01225
01226
01227 struct FindIandU
01228 {
01229 IandUMap iandu;
01230
01231 FindIandU ()
01232 { }
01233
01234 bool operator()( const CapAndItem & cai )
01235 {
01236 PoolItem item( cai.item );
01237 string idx = cai.cap.index();
01238
01239 if ( item.status().staysInstalled() ) {
01240 iandu[idx].installed = item;
01241 }
01242 else if ( item.status().isToBeInstalled() ) {
01243 iandu[idx].uninstalled = item;
01244 }
01245 else if ( item.status().staysUninstalled() ) {
01246 IandUMap::iterator it = iandu.find( idx );
01247
01248 if (it != iandu.end()
01249 && it->second.uninstalled)
01250 {
01251 int cmp = it->second.uninstalled->arch().compare( item->arch() );
01252 if (cmp < 0) {
01253 it->second.uninstalled = item;
01254 }
01255 else if (cmp == 0) {
01256 if (it->second.uninstalled->edition().compare( item->edition() ) < 0) {
01257 it->second.uninstalled = item;
01258 }
01259 }
01260 }
01261 else {
01262 iandu[idx].uninstalled = item;
01263 }
01264 }
01265 return true;
01266 }
01267 };
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277 static bool
01278 transactCaps( const ResPool & pool, const CapSet & caps, bool install, bool soft, std::set<PoolItem_Ref> & added_items )
01279 {
01280 bool result = true;
01281
01282
01283
01284 for (CapSet::const_iterator cit = caps.begin(); cit != caps.end(); ++cit) {
01285
01286
01287
01288 FindIandU callback;
01289 Dep dep( Dep::PROVIDES );
01290 invokeOnEach( pool.byCapabilityIndexBegin( cit->index(), dep ),
01291 pool.byCapabilityIndexEnd( cit->index(), dep ),
01292 resfilter::ByCapMatch( *cit ) ,
01293 functor::functorRef<bool,CapAndItem>(callback) );
01294
01295
01296
01297 for (IandUMap::const_iterator it = callback.iandu.begin(); it != callback.iandu.end(); ++it) {
01298 PoolItem_Ref just_added;
01299 just_added = PoolItem_Ref();
01300 if (!transactItems( it->second.installed, it->second.uninstalled, install, soft, just_added )) {
01301 result = false;
01302 }
01303 else if (just_added) {
01304
01305
01306 added_items.insert( just_added );
01307 }
01308 }
01309
01310 }
01311 return result;
01312 }
01313
01314
01315 struct TransactSupplements : public resfilter::PoolItemFilterFunctor
01316 {
01317 const Resolvable::Kind &_kind;
01318 bool valid;
01319
01320 TransactSupplements( const Resolvable::Kind & kind )
01321 : _kind( kind )
01322 , valid( false )
01323 { }
01324
01325 bool operator()( PoolItem_Ref item )
01326 {
01327
01328 if (item->kind() == _kind
01329 && (item.status().staysInstalled()
01330 || item.status().isToBeInstalled()))
01331 {
01332 valid = true;
01333 return false;
01334 }
01335 return true;
01336 }
01337 };
01338
01339
01340
01341
01342
01343 struct TransactLanguage : public resfilter::PoolItemFilterFunctor
01344 {
01345 Resolver & _resolver;
01346 ResObject::constPtr _langObj;
01347 bool _install;
01348
01349 TransactLanguage( Resolver & r, ResObject::constPtr langObj, bool install )
01350 : _resolver( r )
01351 , _langObj( langObj )
01352 , _install( install )
01353 { }
01354
01355
01356
01357
01358 bool operator()( const CapAndItem & cai )
01359 {
01360
01361
01362 PoolItem_Ref item( cai.item );
01363
01364 CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
01365 if (!supplements.empty()) {
01366
01367 bool valid = false;
01368 for (CapSet::const_iterator it = supplements.begin(); it != supplements.end(); ++it) {
01369
01370 TransactSupplements callback( it->refers() );
01371 invokeOnEach( _resolver.pool().byNameBegin( it->index() ),
01372 _resolver.pool().byNameEnd( it->index() ),
01373 functor::functorRef<bool,PoolItem>( callback ) );
01374 if (callback.valid) {
01375 valid = true;
01376 break;
01377 }
01378 }
01379 if (!valid) {
01380
01381 return true;
01382 }
01383 }
01384
01385 PoolItem_Ref dummy;
01386 if (_install) {
01387 if (item.status().staysUninstalled()) {
01388 transactItems( PoolItem_Ref(), item, _install, true, dummy );
01389 }
01390 }
01391 else {
01392 if (item.status().staysInstalled()) {
01393 transactItems( item, PoolItem_Ref(), _install, true, dummy );
01394 }
01395 }
01396 return true;
01397 }
01398 };
01399
01400
01401
01402
01403
01404
01405
01406
01407 bool
01408 Resolver::transactResObject( ResObject::constPtr robj, bool install,
01409 bool recursive)
01410 {
01411 static std::set<PoolItem_Ref> alreadyTransactedObjects;
01412
01413 if (!recursive) {
01414 alreadyTransactedObjects.clear();
01415 }
01416
01417 if (robj == NULL) {
01418 ERR << "NULL ResObject" << endl;
01419 }
01420 _XDEBUG ( "transactResObject(" << *robj << ", " << (install?"install":"remove") << ")");
01421
01422 if (robj->kind() == ResTraits<Language>::kind) {
01423 TransactLanguage callback( *this, robj, install );
01424 Dep dep( Dep::FRESHENS );
01425 invokeOnEach( pool().byCapabilityIndexBegin( robj->name(), dep ),
01426 pool().byCapabilityIndexEnd( robj->name(), dep ),
01427 functor::functorRef<bool,CapAndItem>( callback ) );
01428
01429 }
01430 std::set<PoolItem_Ref> added;
01431
01432
01433
01434
01435 transactCaps( _pool, robj->dep( Dep::RECOMMENDS ), install, true, added );
01436 transactCaps( _pool, robj->dep( Dep::REQUIRES ), install, false, added );
01437
01438
01439
01440
01441
01442
01443 for (std::set<PoolItem_Ref>::const_iterator it = added.begin(); it != added.end(); ++it) {
01444 if ((*it)->kind() == robj->kind()) {
01445 std::set<PoolItem_Ref>::const_iterator itCmp = alreadyTransactedObjects.find (*it);
01446 if (itCmp == alreadyTransactedObjects.end())
01447 {
01448
01449 alreadyTransactedObjects.insert (*it);
01450 transactResObject( it->resolvable(), install,
01451 true
01452 );
01453 }
01454 }
01455 }
01456
01457
01458 return true;
01459 }
01460
01461
01462
01463
01464
01465
01466
01467 struct TransactKind : public resfilter::PoolItemFilterFunctor
01468 {
01469 Resolver & _resolver;
01470 bool install;
01471 bool result;
01472
01473 TransactKind( Resolver & r )
01474 : _resolver( r )
01475 , result( true )
01476 { }
01477
01478 bool operator()( PoolItem_Ref item )
01479 {
01480 result = _resolver.transactResObject( item.resolvable(), install );
01481 return true;
01482 }
01483 };
01484
01485
01486 bool
01487 Resolver::transactResKind( Resolvable::Kind kind )
01488 {
01489 TransactKind callback (*this);
01490 _XDEBUG( "transactResKind(" << kind << ")" );
01491
01492
01493 callback.install = false;
01494 invokeOnEach( pool().byKindBegin( kind ),
01495 pool().byKindEnd( kind ),
01496 functor::chain( resfilter::ByTransact(), resfilter::ByInstalled ()),
01497 functor::functorRef<bool,PoolItem>( callback ) );
01498
01499
01500 callback.install = true;
01501 invokeOnEach( pool().byKindBegin( kind ),
01502 pool().byKindEnd( kind ),
01503 functor::chain( resfilter::ByTransact(), resfilter::ByUninstalled ()),
01504 functor::functorRef<bool,PoolItem>( callback ) );
01505
01506 return callback.result;
01507 }
01508
01509
01510 struct TransactReset : public resfilter::PoolItemFilterFunctor
01511 {
01512 ResStatus::TransactByValue _causer;
01513 TransactReset( ResStatus::TransactByValue causer )
01514 : _causer( causer )
01515 { }
01516
01517 bool operator()( PoolItem_Ref item )
01518 {
01519 item.status().resetTransact( _causer );
01520 return true;
01521 }
01522 };
01523
01524
01525 void
01526 Resolver::transactReset( ResStatus::TransactByValue causer )
01527 {
01528 TransactReset info( causer );
01529 MIL << "transactReset(" << causer << ")" << endl;
01530 invokeOnEach ( _pool.begin(), _pool.end(),
01531 resfilter::ByTransact( ),
01532 functor::functorRef<bool,PoolItem>(info) );
01533 return;
01534 }
01535
01537 };
01540 };
01543 };
01545