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