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