Resolver.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /* Resolver.cc
00003  *
00004  * Copyright (C) 2000-2002 Ximian, Inc.
00005  * Copyright (C) 2005 SUSE Linux Products GmbH
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019  * 02111-1307, USA.
00020  */
00021 
00022 #include <sys/utsname.h>
00023 
00024 #include "zypp/solver/detail/Resolver.h"
00025 #include "zypp/solver/detail/Helper.h"
00026 
00027 #include "zypp/CapSet.h"
00028 #include "zypp/base/Logger.h"
00029 #include "zypp/base/String.h"
00030 #include "zypp/base/Gettext.h"
00031 
00032 #include "zypp/base/Algorithm.h"
00033 #include "zypp/ResPool.h"
00034 #include "zypp/ResFilters.h"
00035 #include "zypp/CapFilters.h"
00036 #include "zypp/ZYppFactory.h"
00037 #include "zypp/SystemResObject.h"
00038 
00039 
00040 
00042 namespace zypp
00043 { 
00044 
00045   namespace solver
00046   { 
00047 
00048     namespace detail
00049     { 
00050 
00051 using namespace std;
00052 
00053 IMPL_PTR_TYPE(Resolver);
00054 
00055 //---------------------------------------------------------------------------
00056 
00057 std::ostream &
00058 Resolver::dumpOn( std::ostream & os ) const
00059 {
00060     return os << "<resolver/>";
00061 }
00062 
00063 // Generating a system resolvable in the pool in order to trigger
00064 // modaliases and hals  
00065 void assertSystemResObjectInPool()
00066 {
00067   ResPool pool( getZYpp()->pool() );
00068   if ( pool.byKindBegin<SystemResObject>()
00069        == pool.byKindEnd<SystemResObject>() )
00070     {
00071       // SystemResObject is missing in the pool ==> insert
00072       ResStore store;
00073       store.insert( SystemResObject::instance() );
00074       getZYpp()->addResolvables( store, true ); // true = is installed
00075     }
00076 
00077   // set lock
00078   if ( ! pool.byKindBegin<SystemResObject>()
00079          ->status().setLock( true, ResStatus::USER ) )
00080     {
00081       WAR << "Unable to set SystemResObject to lock" << endl;
00082     }
00083 }       
00084 
00085 //---------------------------------------------------------------------------
00086 
00087 Resolver::Resolver (const ResPool & pool)
00088     : _pool (pool)
00089     , _timeout_seconds (0)
00090     , _verifying (false)
00091     , _testing (false)
00092     , _valid_solution_count (0)
00093     , _best_context (NULL)
00094     , _timed_out (false)
00095     , _forceResolve (false)
00096     , _upgradeMode (false)
00097 {
00098     struct utsname buf;
00099     if (uname (&buf) < 0) {
00100         ERR << "Can't determine system architecture" << endl;
00101     }
00102     else {
00103         MIL << "System architecture is '" << buf.machine << "'" << endl;
00104         _architecture = Arch(buf.machine);
00105     }
00106 }
00107 
00108 
00109 Resolver::~Resolver()
00110 {
00111 }
00112 
00113 //---------------------------------------------------------------------------
00114 
00115 ResPool
00116 Resolver::pool (void) const
00117 {
00118     return _pool;
00119 }
00120 
00121 void
00122 Resolver::reset (void)
00123 {
00124     _timeout_seconds = 0;
00125     _verifying = false;
00126 
00127     _initial_items.clear();
00128 
00129     _items_to_install.clear();
00130     _items_to_remove.clear();
00131     _items_to_verify.clear();
00132     _items_to_establish.clear();
00133 
00134     _extra_caps.clear();
00135     _extra_conflicts.clear();
00136 
00137     _pending_queues.clear();
00138     _pruned_queues.clear();
00139     _complete_queues.clear();
00140     _deferred_queues.clear();
00141     _invalid_queues.clear();
00142 
00143     _valid_solution_count = 0;
00144 
00145     _best_context = NULL;
00146     _timed_out = false;
00147 }
00148 
00149 
00150 ResolverContext_Ptr
00151 Resolver::context (void) const
00152 {
00153     if (_best_context) return _best_context;
00154     if (_invalid_queues.empty()) return NULL;
00155     ResolverQueue_Ptr invalid = _invalid_queues.front();
00156     return invalid->context();
00157 }
00158 
00159 //---------------------------------------------------------------------------
00160 
00161 void
00162 Resolver::addSubscribedSource (Source_Ref source)
00163 {
00164     _subscribed.insert(source);
00165 }
00166 
00167 void
00168 Resolver::addPoolItemToInstall (PoolItem_Ref item)
00169 {
00170     bool found = false;
00171     for (PoolItemList::const_iterator iter = _items_to_remove.begin();
00172          iter != _items_to_remove.end(); iter++) {
00173         if (*iter == item) {
00174             _items_to_remove.remove(*iter);
00175             found = true;
00176             break;
00177         }
00178     }
00179     if (!found)
00180         _items_to_install.push_back (item);
00181 }
00182 
00183 
00184 void
00185 Resolver::addPoolItemsToInstallFromList (PoolItemList & rl)
00186 {
00187     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00188         addPoolItemToInstall (*iter);
00189     }
00190 }
00191 
00192 
00193 void
00194 Resolver::addPoolItemToRemove (PoolItem_Ref item)
00195 {
00196     bool found = false;
00197     for (PoolItemList::const_iterator iter = _items_to_install.begin();
00198          iter != _items_to_install.end(); iter++) {
00199         if (*iter == item) {
00200             _items_to_install.remove(*iter);
00201             found = true;
00202             break;
00203         }
00204     }
00205     if (!found)
00206         _items_to_remove.push_back (item);
00207 }
00208 
00209 
00210 void
00211 Resolver::addPoolItemsToRemoveFromList (PoolItemList & rl)
00212 {
00213     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00214         addPoolItemToRemove (*iter);
00215     }
00216 }
00217 
00218 
00219 void
00220 Resolver::addPoolItemToEstablish (PoolItem_Ref item)
00221 {
00222     _items_to_establish.push_back (item);
00223 }
00224 
00225 
00226 void
00227 Resolver::addPoolItemsToEstablishFromList (PoolItemList & rl)
00228 {
00229     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00230         addPoolItemToEstablish (*iter);
00231     }
00232 }
00233 
00234 
00235 void
00236 Resolver::addPoolItemToVerify (PoolItem_Ref item)
00237 {
00238 #if 0
00239 
00240   struct {
00242     bool operator()( PoolItem_Ref lhs, PoolItem_Ref rhs ) const
00243     {
00244       int res = lhs->name().compare( rhs->name() );
00245       if ( res )
00246         return res == -1; // lhs < rhs ?
00247       // here: lhs == rhs, so compare edition:
00248       return lhs->edition() < rhs->edition();
00249     }
00250   } order;
00251 #endif
00252 
00253     _items_to_verify.push_back (item);
00254 
00255 #warning Should order by name (and probably edition since with zypp we could have multiple editions installed in parallel)
00256 //    _items_to_verify.sort (order);                    //(GCompareFunc) rc_item_compare_name);
00257 }
00258 
00259 
00260 void
00261 Resolver::addExtraCapability (const Capability & capability)
00262 {
00263     _extra_caps.insert (capability);
00264 }
00265 
00266 
00267 void
00268 Resolver::addExtraConflict (const Capability & capability)
00269 {
00270     _extra_conflicts.insert (capability);
00271 }
00272 
00273 
00274 void
00275 Resolver::addIgnoreConflict (const PoolItem_Ref item,
00276                    const Capability & capability)
00277 {
00278     _ignoreConflicts.insert(make_pair(item, capability));
00279 }
00280 
00281 
00282 void
00283 Resolver::addIgnoreRequires (const PoolItem_Ref item,
00284                              const Capability & capability)
00285 {
00286     _ignoreRequires.insert(make_pair(item, capability));
00287 }
00288 
00289 void
00290 Resolver::addIgnoreObsoletes (const PoolItem_Ref item,
00291                               const Capability & capability)
00292 {
00293     _ignoreObsoletes.insert(make_pair(item, capability));
00294 }
00295 
00296 void
00297 Resolver::addIgnoreInstalledItem (const PoolItem_Ref item)
00298 {
00299     _ignoreInstalledItem.push_back (item);
00300 }
00301 
00302 void
00303 Resolver::addIgnoreArchitectureItem (const PoolItem_Ref item)
00304 {
00305     _ignoreArchitectureItem.push_back (item);
00306 }
00307 
00308 
00309 //---------------------------------------------------------------------------
00310 
00311 struct VerifySystem : public resfilter::PoolItemFilterFunctor
00312 {
00313     Resolver & resolver;
00314 
00315     VerifySystem (Resolver & r)
00316         : resolver (r)
00317     { }
00318 
00319     bool operator()( PoolItem_Ref provider )
00320     {
00321         resolver.addPoolItemToVerify (provider);
00322         return true;
00323     }
00324 };
00325 
00326 
00327 bool
00328 Resolver::verifySystem (void)
00329 {
00330     _DEBUG( "Resolver::verifySystem()" );
00331 
00332     VerifySystem info (*this);
00333 
00334     invokeOnEach( pool().byKindBegin( ResTraits<Package>::kind ),
00335                   pool().byKindEnd( ResTraits<Package>::kind ),
00336                   resfilter::ByInstalled ( ),
00337                   functor::functorRef<bool,PoolItem>(info) );
00338 
00339 
00340     _verifying = true;
00341 
00342     return resolveDependencies ();
00343 }
00344 
00345 
00346 //---------------------------------------------------------------------------
00347 
00348 // copy marked item from solution back to pool
00349 // if data != NULL, set as APPL_LOW (from establishPool())
00350 
00351 static void
00352 solution_to_pool (PoolItem_Ref item, const ResStatus & status, void *data)
00353 {
00354     bool r;
00355 
00356     if (status.isToBeInstalled()) {
00357         r = item.status().setToBeInstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00358         _XDEBUG("solution_to_pool(" << item << ", " << status << ") install !" << r);
00359     }
00360     else if (status.isToBeUninstalledDueToUpgrade()) {
00361         r = item.status().setToBeUninstalledDueToUpgrade( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00362         _XDEBUG("solution_to_pool(" << item << ", " << status << ") upgrade !" << r);
00363     }
00364     else if (status.isToBeUninstalled()) {
00365         r = item.status().setToBeUninstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00366         _XDEBUG("solution_to_pool(" << item << ", " << status << ") remove !" << r);
00367     }
00368     else if (status.isIncomplete()
00369              || status.isNeeded()) {
00370         r = item.status().setIncomplete();
00371         _XDEBUG("solution_to_pool(" << item << ", " << status << ") incomplete !" << r);
00372     }
00373     else if (status.isUnneeded()) {
00374         r = item.status().setUnneeded();
00375         _XDEBUG("solution_to_pool(" << item << ", " << status << ") unneeded !" << r);
00376     }
00377     else if (status.isSatisfied()) {
00378         r = item.status().setSatisfied();
00379         _XDEBUG("solution_to_pool(" << item << ", " << status << ") satisfied !" << r);
00380     } else {
00381         _XDEBUG("solution_to_pool(" << item << ", " << status << ") unchanged !");
00382     }
00383     return;
00384 }
00385 
00386 
00387 //---------------------------------------------------------------------------
00388 // establish state
00389 
00390 struct EstablishState
00391 {
00392     Resolver & resolver;
00393 
00394     EstablishState (Resolver & r)
00395         : resolver (r)
00396     { }
00397 
00398     bool operator()( PoolItem_Ref provider )
00399     {
00400         resolver.addPoolItemToEstablish (provider);
00401         return true;
00402     }
00403 };
00404 
00405 
00406 void
00407 Resolver::establishState( ResolverContext_Ptr context )
00408 {
00409     _DEBUG( "Resolver::establishState ()" );
00410     typedef list<Resolvable::Kind> KindList;
00411     static KindList ordered;
00412     if (ordered.empty()) {
00413         ordered.push_back (ResTraits<zypp::Atom>::kind);
00414         ordered.push_back (ResTraits<zypp::Message>::kind);
00415         ordered.push_back (ResTraits<zypp::Script>::kind);
00416         ordered.push_back (ResTraits<zypp::Patch>::kind);
00417         ordered.push_back (ResTraits<zypp::Pattern>::kind);
00418         ordered.push_back (ResTraits<zypp::Product>::kind);
00419     }
00420 
00421     if (context == NULL)
00422         context = new ResolverContext(_pool, _architecture);
00423 
00424     context->setEstablishing (true);
00425     context->setIgnoreCababilities (_ignoreConflicts,
00426                                     _ignoreRequires,
00427                                     _ignoreObsoletes,
00428                                     _ignoreInstalledItem,
00429                                     _ignoreArchitectureItem);
00430     context->setForceResolve( _forceResolve );
00431     context->setUpgradeMode( _upgradeMode );
00432 
00433     for (KindList::const_iterator iter = ordered.begin(); iter != ordered.end(); iter++) {
00434         const Resolvable::Kind kind = *iter;
00435 
00436         _XDEBUG( "establishing state for kind " << kind.asString() );
00437 
00438         //world()->foreachResItemByKind (kind, trial_establish_cb, this);
00439 
00440         EstablishState info (*this);
00441 
00442         invokeOnEach( pool().byKindBegin( kind ),
00443                       pool().byKindEnd( kind ),
00444                       functor::functorRef<bool,PoolItem>(info) );
00445 
00446         // process the queue
00447         resolveDependencies( context );
00448 
00449         reset();
00450     }
00451 
00452     context->setEstablishing (false);
00453 
00454     _best_context = context;
00455 
00456     return;
00457 }
00458 
00459 
00460 bool
00461 Resolver::establishPool ()
00462 {
00463     MIL << "Resolver::establishPool()" << endl;
00464 
00465     establishState ();                                          // establish !
00466     ResolverContext_Ptr solution = bestContext();
00467 
00468     if (solution) {                                             // copy solution back to pool
00469         solution->foreachMarked (solution_to_pool, (void *)1);  // as APPL_LOW
00470     }
00471     else {
00472         ERR << "establishState did not return a bestContext" << endl;
00473         return false;
00474     }
00475 
00476     return true;
00477 }
00478 
00479 
00480 //---------------------------------------------------------------------------
00481 // freshen state
00482 
00483 typedef map<string, PoolItem_Ref> FreshenMap;
00484 
00485 // add item to itemmap
00486 //  check for item with same name and only keep
00487 //  best architecture, best version
00488 
00489 static void
00490 addToFreshen( PoolItem_Ref item, FreshenMap & itemmap )
00491 {
00492     FreshenMap::iterator it = itemmap.find( item->name() );
00493     if (it != itemmap.end()) {                                  // item with same name found
00494         int cmp = it->second->arch().compare( item->arch() );
00495         if (cmp < 0) {                                          // new item has better arch
00496             it->second = item;
00497         }
00498         else if (cmp == 0) {                                    // new item has equal arch
00499             if (it->second->edition().compare( item->edition() ) < 0) {
00500                 it->second = item;                              // new item has better edition
00501             }
00502         }
00503     }
00504     else {
00505         itemmap[item->name()] = item;
00506     }
00507     return;
00508 }
00509 
00510 
00511 struct FreshenState
00512 {
00513     FreshenMap itemmap;
00514 
00515     FreshenState()
00516     { }
00517 
00518     bool operator()( PoolItem_Ref item)
00519     {
00520         CapSet freshens( item->dep( Dep::FRESHENS ) );
00521         if (!freshens.empty()) {
00522             addToFreshen( item, itemmap );
00523         }
00524         else {                                  // if no freshens, look at supplements
00525             // Also regarding supplements e.g. in order to recognize
00526             // modalias dependencies. Bug #163140
00527             CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
00528             if (!supplements.empty()) {
00529                 addToFreshen( item, itemmap );
00530             }
00531         }
00532         return true;
00533     }
00534 };
00535 
00536 
00537 void
00538 Resolver::freshenState( ResolverContext_Ptr context )
00539 {
00540     _DEBUG( "Resolver::freshenState ()" );
00541 
00542     if (context == NULL)
00543         context = new ResolverContext( _pool, _architecture );
00544 
00545     context->setEstablishing( true );
00546     context->setIgnoreCababilities( _ignoreConflicts,
00547                                     _ignoreRequires,
00548                                     _ignoreObsoletes,
00549                                     _ignoreInstalledItem,
00550                                     _ignoreArchitectureItem );
00551     context->setForceResolve( _forceResolve );
00552     context->setUpgradeMode( _upgradeMode );
00553 
00554     FreshenState info;
00555 
00556     // collect items to be established
00557 
00558     invokeOnEach( pool().byKindBegin( ResTraits<zypp::Package>::kind ),
00559                       pool().byKindEnd( ResTraits<zypp::Package>::kind ),
00560                       functor::functorRef<bool,PoolItem>(info) );
00561 
00562     // schedule all collected items for establish
00563 
00564     for (FreshenMap::iterator it = info.itemmap.begin(); it != info.itemmap.end(); ++it) {
00565         addPoolItemToEstablish( it->second );
00566     }
00567 
00568     // process the queue
00569     resolveDependencies( context );
00570 
00571     reset();
00572 
00573     context->setEstablishing( false );
00574 
00575     _best_context = context;
00576 
00577     return;
00578 }
00579 
00580 
00581 bool
00582 Resolver::freshenPool ()
00583 {
00584     MIL << "Resolver::freshenPool()" << endl;
00585 
00586     freshenState ();                                            // establish all packages with freshens !
00587     ResolverContext_Ptr solution = bestContext();
00588 
00589     if (solution) {                                             // copy solution back to pool
00590         solution->foreachMarked (solution_to_pool, (void *)1);  // as APPL_LOW
00591     }
00592     else {
00593         ERR << "freshenState did not return a bestContext" << endl;
00594         return false;
00595     }
00596 
00597     return true;
00598 }
00599 
00600 //---------------------------------------------------------------------------
00601 
00602 bool
00603 Resolver::resolveDependencies (const ResolverContext_Ptr context)
00604 {
00605 
00606     time_t t_start, t_now;
00607 
00608     MIL << "Resolver::resolveDependencies()" << endl;
00609 
00610     _pending_queues.clear();
00611     _pruned_queues.clear();
00612     _complete_queues.clear();
00613     _deferred_queues.clear();
00614     _invalid_queues.clear();
00615     _valid_solution_count = 0;
00616     _best_context = NULL;
00617 
00618 #warning local items disabled
00619 #if 0
00620     bool have_local_items = false;
00621 
00622     /* Walk through are list of to-be-installed packages and see if any of them are local. */
00623 
00624     for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00625         if ((*iter)->local()) {
00626             have_local_items = true;
00627             break;
00628         }
00629     }
00630 
00631     World_Ptr the_world = world();
00632     StoreWorld_Ptr local_world = NULL;
00633     MultiWorld_Ptr local_multiworld = NULL;
00634 
00635     Channel_Ptr local_channel = NULL;
00636 
00637     if (have_local_items) {
00638         local_multiworld = new MultiWorld();
00639         local_world = new StoreWorld();
00640 
00641         local_channel = new Channel ("", "Local ResItems", "@local", "");
00642 
00643         local_world->addChannel (local_channel);
00644 
00645         local_multiworld->addSubworld (local_world);
00646         local_multiworld->addSubworld (the_world);
00647 
00648         the_world = local_multiworld;
00649     }
00650 #endif
00651 
00652     // create initial_queue
00653 
00654     ResolverQueue_Ptr initial_queue = new ResolverQueue(_pool, _architecture, context);
00655 
00656     // Initialize all ignoring dependencies
00657     initial_queue->context()->setIgnoreCababilities (_ignoreConflicts,
00658                                     _ignoreRequires,
00659                                     _ignoreObsoletes,
00660                                     _ignoreInstalledItem,
00661                                     _ignoreArchitectureItem);
00662     initial_queue->context()->setForceResolve( _forceResolve );
00663     initial_queue->context()->setUpgradeMode( _upgradeMode );
00664 
00665     /* If this is a verify, we do a "soft resolution" */
00666 
00667     initial_queue->context()->setVerifying( _verifying );
00668 
00669     /* Add extra items. */
00670 
00671     for (QueueItemList::const_iterator iter = _initial_items.begin(); iter != _initial_items.end(); iter++) {
00672         initial_queue->addItem (*iter);
00673     }
00674 
00675     for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00676         PoolItem_Ref r = *iter;
00677 
00678 #warning local items disabled
00679 #if 0
00680         /* Add local packages to our dummy channel. */
00681         if (r->local()) {
00682             assert (local_channel != NULL);
00683             ResItem_Ptr r1 = const_pointer_cast<ResItem>(r);
00684             r1->setChannel (local_channel);
00685             local_world->addPoolItem_Ref (r);
00686         }
00687 #endif
00688         initial_queue->addPoolItemToInstall (r);
00689     }
00690 
00691     for (PoolItemList::const_iterator iter = _items_to_remove.begin(); iter != _items_to_remove.end(); iter++) {
00692         if (!_upgradeMode)
00693             initial_queue->addPoolItemToRemove (*iter, true /* remove-only mode */);
00694         else
00695             //   Checking old dependencies for packages which will be updated.
00696             //   E.g. foo provides a dependecy which foo-new does not provides anymore.
00697             //   So check, if there is a packages installed which requires foo.
00698             //   Testcase exercise-bug150844-test.xml
00699             //   Testcase Bug156439-test.xml
00700             initial_queue->addPoolItemToRemove (*iter, false /* no remove-only mode */);
00701     }
00702 
00703     for (PoolItemList::const_iterator iter = _items_to_verify.begin(); iter != _items_to_verify.end(); iter++) {
00704         initial_queue->addPoolItemToVerify (*iter);
00705     }
00706 
00707     for (PoolItemList::const_iterator iter = _items_to_establish.begin(); iter != _items_to_establish.end(); iter++) {
00708         initial_queue->addPoolItemToEstablish (*iter);
00709     }
00710 
00711     for (CapSet::const_iterator iter = _extra_caps.begin(); iter != _extra_caps.end(); iter++) {
00712         initial_queue->addExtraCapability (*iter);
00713     }
00714 
00715     for (CapSet::const_iterator iter = _extra_conflicts.begin(); iter != _extra_conflicts.end(); iter++) {
00716         initial_queue->addExtraConflict (*iter);
00717     }
00718 
00719     // Adding System resolvable
00720     assertSystemResObjectInPool();
00721 
00722     _XDEBUG( "Initial Queue: [" << *initial_queue << "]" );
00723 
00724     if (initial_queue->isEmpty()) {
00725         INT << "Empty Queue, nothing to resolve" << endl;
00726 
00727         return true;
00728     }
00729 
00730     _best_context = NULL;
00731 
00732     _pending_queues.push_front (initial_queue);
00733 
00734     time (&t_start);
00735 
00736     while (!_pending_queues.empty()) {
00737 
00738         _DEBUG( "Pend " << (long) _pending_queues.size()
00739                               << " / Cmpl " << (long) _complete_queues.size()
00740                               << " / Prun " << (long) _pruned_queues.size()
00741                               << " / Defr " << (long) _deferred_queues.size()
00742                               << " / Invl " << (long) _invalid_queues.size() );
00743 
00744               if (_timeout_seconds > 0) {
00745                     time (&t_now);
00746                     if (difftime (t_now, t_start) > _timeout_seconds) {
00747                         _timed_out = true;
00748                     break;
00749                 }
00750             }
00751 
00752             ResolverQueue_Ptr queue = _pending_queues.front();
00753             _pending_queues.pop_front();
00754             ResolverContext_Ptr context = queue->context();
00755 
00756             queue->process();
00757 
00758         if (queue->isInvalid ()) {
00759 
00760             _XDEBUG( "Invalid Queue\n" );
00761             _invalid_queues.push_back(queue);
00762 
00763         } else if (queue->isEmpty ()) {
00764 
00765             _XDEBUG( "Empty Queue\n" );
00766 
00767             _complete_queues.push_back(queue);
00768 
00769             ++_valid_solution_count;
00770 
00771             /* Compare this solution to our previous favorite.  In the case of a tie,
00772                the first solution wins --- yeah, I know this is lame, but it shouldn't
00773                be an issue too much of the time. */
00774 
00775             if (_best_context == NULL
00776                 || _best_context->compare (context) < 0)
00777             {
00778                 _best_context = context;
00779             }
00780 
00781         } else if (_best_context != NULL
00782                    && _best_context->partialCompare (context) > 0) {
00783 
00784             /* If we aren't currently as good as our previous best complete solution,
00785                this solution gets pruned. */
00786 
00787             _XDEBUG( "PRUNED!" );
00788 
00789             _pruned_queues.push_back(queue);
00790 
00791         } else {
00792 
00793             /* If our queue is isn't empty and isn't invalid, that can only mean
00794                one thing: we are down to nothing but branches. */
00795 
00796             queue->splitFirstBranch (_pending_queues, _deferred_queues);
00797         }
00798 
00799         /* If we have run out of pending queues w/o finding any solutions,
00800            and if we have deferred queues, make the first deferred queue
00801            pending. */
00802 
00803         if (_pending_queues.empty()
00804             && _complete_queues.empty()
00805             && !_deferred_queues.empty()) {
00806             _pending_queues.push_back(_deferred_queues.front());
00807         }
00808     }
00809     _DEBUG("Pend " << (long) _pending_queues.size()
00810                    << " / Cmpl " << (long) _complete_queues.size()
00811                    << " / Prun " << (long) _pruned_queues.size()
00812                    << " / Defr " << (long) _deferred_queues.size()
00813                    << " / Invl " << (long) _invalid_queues.size() );
00814 
00815     return _best_context && _best_context->isValid();
00816 }
00817 
00818 
00819 //----------------------------------------------------------------------------
00820 // undo
00821 
00822 struct UndoTransact : public resfilter::PoolItemFilterFunctor
00823 {
00824     UndoTransact ()
00825     { }
00826 
00827     bool operator()( PoolItem_Ref item )                // only transacts() items go here
00828     {
00829         item.status().resetTransact( ResStatus::APPL_LOW );// clear any solver/establish transactions
00830         return true;
00831     }
00832 };
00833 
00834 void
00835 Resolver::undo(void)
00836 {
00837     UndoTransact info;
00838     MIL << "*** undo ***" << endl;
00839     invokeOnEach ( _pool.begin(), _pool.end(),
00840                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
00841                    functor::functorRef<bool,PoolItem>(info) );
00842     // These conflict should be ignored of the concering item
00843     _ignoreConflicts.clear();
00844     // These requires should be ignored of the concering item
00845     _ignoreRequires.clear();
00846     // These obsoletes should be ignored of the concering item
00847     _ignoreObsoletes.clear();
00848     // Ignore architecture of the item
00849     _ignoreArchitecture.clear();
00850     // Ignore the status "installed" of the item
00851     _ignoreInstalledItem.clear();
00852     // Ignore the architecture of the item
00853     _ignoreArchitectureItem.clear();
00854 
00855 
00856     return;
00857 }
00858 
00859 //----------------------------------------------------------------------------
00860 // resolvePool
00861 
00862 struct CollectTransact : public resfilter::PoolItemFilterFunctor
00863 {
00864     Resolver & resolver;
00865 
00866     CollectTransact (Resolver & r)
00867         : resolver (r)
00868     { }
00869 
00870     bool operator()( PoolItem_Ref item )                // only transacts() items go here
00871     {
00872         ResStatus status = item.status();
00873         _XDEBUG( "CollectTransact(" << item << ")" );
00874         bool by_solver = (status.isBySolver() || status.isByApplLow());
00875 
00876         if (by_solver) {
00877             item.status().resetTransact( ResStatus::APPL_LOW );// clear any solver/establish transactions
00878             return true;                                // back out here, dont re-queue former solver result
00879         }
00880 
00881         if (status.isToBeInstalled()) {
00882             resolver.addPoolItemToInstall(item);        // -> install!
00883         }
00884         if (status.isToBeUninstalled()) {
00885             resolver.addPoolItemToRemove(item);         // -> remove !
00886         }
00887         if (status.isIncomplete()) {                    // incomplete (re-install needed)
00888             PoolItem_Ref reinstall = Helper::findReinstallItem (resolver.pool(), item);
00889             if (reinstall) {
00890                 MIL << "Reinstall " << reinstall << " for incomplete " << item << endl;
00891                 resolver.addPoolItemToInstall(reinstall);       // -> install!
00892             }
00893             else {
00894                 WAR << "Can't find " << item << " for re-installation" << endl;
00895             }
00896         }
00897         return true;
00898     }
00899 };
00900 
00901 
00902 static void
00903 show_pool( ResPool pool )
00904 {
00905     int count = 1;
00906     static bool full_pool_shown = true;
00907 
00908     _XDEBUG( "---------------------------------------" );
00909     for (ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it, ++count) {
00910 
00911         if (!full_pool_shown                                    // show item if not shown all before
00912             || it->status().transacts()                         // or transacts
00913             || !it->status().isUndetermined())                  // or established status
00914         {
00915             _DEBUG( count << ": " << *it );
00916         }
00917     }
00918     _XDEBUG( "---------------------------------------" );
00919     full_pool_shown = true;
00920 }
00921 
00922 //  This function loops over the pool and grabs
00923 //  all item.status().transacts() and item.status().byUser()
00924 //  It clears all previous bySolver() states also
00925 //
00926 //  Every toBeInstalled is passed to zypp::solver:detail::Resolver.addPoolItemToInstall()
00927 //  Every toBeUninstalled is passed to zypp::solver:detail::Resolver.addPoolItemToRemove()
00928 //
00929 //  Then zypp::solver:detail::Resolver.resolveDependencies() is called.
00930 //
00931 //  zypp::solver:detail::Resolver then returns a ResolverContext via bestContext() which
00932 //  describes the best solution. If bestContext() is NULL, no solution was found.
00933 //
00934 //  ResolverContext has a foreachMarked() iterator function which loops over all
00935 //  items of the solutions. These must be written back to the pool.
00936 
00937 
00938 bool
00939 Resolver::resolvePool ()
00940 {
00941 
00942     CollectTransact info (*this);
00943 
00944     // cleanup before next run
00945     reset();
00946 
00947 #if 1
00948 
00949     MIL << "Resolver::resolvePool()" << endl;
00950     _XDEBUG( "Pool before resolve" );
00951     show_pool( _pool );
00952 
00953 #endif
00954     invokeOnEach ( _pool.begin(), _pool.end(),
00955                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
00956                    functor::functorRef<bool,PoolItem>(info) );
00957 
00958     bool have_solution = resolveDependencies ();                // resolve !
00959 
00960     if (have_solution) {                                        // copy solution back to pool
00961         MIL << "Have solution, copying back to pool" << endl;
00962         ResolverContext_Ptr solution = bestContext();
00963         solution->foreachMarked (solution_to_pool, NULL);
00964 #if 1
00965         _XDEBUG( "Pool after resolve" );
00966         show_pool( _pool );
00967 #endif
00968     }
00969     else {
00970         MIL << "!!! Have NO solution !!!" << endl;
00971     }
00972     return have_solution;
00973 }
00974 
00975 //-----------------------------------------------------------------------------
00976 
00977 //
00978 // UI Helper
00979 // do a single (install/uninstall) transaction
00980 //  if a previously uninstalled item was just set to-be-installed, return it as 'added'
00981 
00982 static bool
00983 transactItems( PoolItem_Ref installed, PoolItem_Ref uninstalled, bool install, bool soft, PoolItem_Ref & added )
00984 {
00985         if (install) {
00986             if (compareByNVRA (installed.resolvable(), uninstalled.resolvable()) != 0) { // do not update itself Bug 174290
00987                 if (uninstalled
00988                     && !uninstalled.status().isLocked())
00989                 {
00990                     bool adding;        // check if we're succeeding with transaction
00991                     if (soft)
00992                         adding = uninstalled.status().setSoftTransact( true, ResStatus::APPL_LOW );
00993                     else
00994                         adding = uninstalled.status().setTransact( true, ResStatus::APPL_LOW );
00995                     if (adding) // if succeeded, return it as 'just added'
00996                         added = uninstalled;
00997                 }
00998                 if (installed
00999                     && !installed.status().isLocked())
01000                 {
01001                     installed.status().resetTransact( ResStatus::APPL_LOW );
01002                 }
01003             }
01004         } else {
01005             // uninstall
01006             if (uninstalled
01007                 && !uninstalled.status().isLocked())
01008             {
01009                 uninstalled.status().resetTransact( ResStatus::APPL_LOW );
01010             }
01011             if (installed
01012                 && !installed.status().isLocked())
01013             {
01014                 if (soft)
01015                     installed.status().setSoftTransact( true, ResStatus::APPL_LOW );
01016                 else
01017                     installed.status().setTransact( true, ResStatus::APPL_LOW );
01018             }
01019         }
01020         if (!uninstalled
01021             && !installed)
01022         {
01023             return false;
01024         }
01025     return true;
01026 }
01027 
01028 
01029 typedef struct { PoolItem_Ref installed; PoolItem_Ref uninstalled; } IandU;
01030 typedef map<string, IandU> IandUMap;
01031 
01032 // find best available providers for requested capability index
01033 // (use capability index instead of name in order to find e.g. ccb vs. x11)
01034 
01035 struct FindIandU
01036 {
01037     IandUMap iandu;             // install, and best uninstalled
01038 
01039     FindIandU ()
01040     { }
01041 
01042     bool operator()( const CapAndItem & cai )
01043     {
01044         PoolItem item( cai.item );
01045         string idx = cai.cap.index();
01046 
01047         if ( item.status().staysInstalled() ) {
01048             iandu[idx].installed = item;
01049         }
01050         else if ( item.status().isToBeInstalled() ) {                   // prefer already to-be-installed
01051             iandu[idx].uninstalled = item;
01052         }
01053         else if ( item.status().staysUninstalled() ) {                  // only look at uninstalled
01054             IandUMap::iterator it = iandu.find( idx );
01055 
01056             if (it != iandu.end()
01057                 && it->second.uninstalled)
01058             {                                                           // uninstalled with same name found
01059                 int cmp = it->second.uninstalled->arch().compare( item->arch() );
01060                 if (cmp < 0) {                                          // new item has better arch
01061                     it->second.uninstalled = item;
01062                 }
01063                 else if (cmp == 0) {                                    // new item has equal arch
01064                     if (it->second.uninstalled->edition().compare( item->edition() ) < 0) {
01065                         it->second.uninstalled = item;                  // new item has better edition
01066                     }
01067                 }
01068             }
01069             else {
01070                 iandu[idx].uninstalled = item;
01071             }
01072         }
01073         return true;
01074     }
01075 };
01076 
01077 
01078 //
01079 // transact list of capabilities (requires or recommends)
01080 //  return false if one couldn't be matched
01081 //
01082 // see Resolver::transactResObject
01083 //
01084 
01085 static bool
01086 transactCaps( const ResPool & pool, const CapSet & caps, bool install, bool soft, std::list<PoolItem_Ref> & added_items )
01087 {
01088     bool result = true;
01089 
01090     // loop over capabilities and find (best) matching provider
01091 
01092     for (CapSet::const_iterator cit = caps.begin(); cit != caps.end(); ++cit) {
01093 
01094         // find best providers of requested capability
01095 
01096         FindIandU callback;
01097         Dep dep( Dep::PROVIDES );
01098         invokeOnEach( pool.byCapabilityIndexBegin( cit->index(), dep ),
01099                       pool.byCapabilityIndexEnd( cit->index(), dep ),
01100                       resfilter::ByCapMatch( *cit ) ,
01101                       functor::functorRef<bool,CapAndItem>(callback) );
01102 
01103         // loop through providers and transact them accordingly
01104 
01105         for (IandUMap::const_iterator it = callback.iandu.begin(); it !=  callback.iandu.end(); ++it) {
01106             PoolItem_Ref just_added;
01107             just_added = PoolItem_Ref();
01108             if (!transactItems( it->second.installed, it->second.uninstalled, install, soft, just_added )) {
01109                 result = false;
01110             }
01111             else if (just_added) {
01112                 // transactItems just selected an item of the same kind we're currently processing
01113                 // add it to the list and handle it equivalent to the origin item
01114                 added_items.push_back( just_added );
01115             }
01116         }
01117         
01118     }
01119     return result;
01120 }
01121 
01122 
01123 struct TransactSupplements : public resfilter::PoolItemFilterFunctor
01124 {
01125     const Resolvable::Kind &_kind;
01126     bool valid;
01127 
01128     TransactSupplements( const Resolvable::Kind & kind )
01129         : _kind( kind )
01130         , valid( false )
01131     { }
01132 
01133     bool operator()( PoolItem_Ref item )
01134     {
01135 //      MIL << "TransactSupplements(" << item << ")" << endl;
01136         if (item->kind() == _kind
01137             && (item.status().staysInstalled()
01138                 || item.status().isToBeInstalled()))
01139         {
01140             valid = true;
01141             return false;               // end search here
01142         }
01143         return true;
01144     }
01145 };
01146 
01147 //
01148 // transact due to a language dependency
01149 // -> look through the pool and run transactResObject() accordingly
01150 
01151 struct TransactLanguage : public resfilter::PoolItemFilterFunctor
01152 {
01153     Resolver & _resolver;
01154     ResObject::constPtr _langObj;
01155     bool _install;
01156 
01157     TransactLanguage( Resolver & r, ResObject::constPtr langObj, bool install )
01158         : _resolver( r )
01159         , _langObj( langObj )
01160         , _install( install )
01161     { }
01162 
01163     /* item has a freshens on _langObj
01164         _langObj just transacted to _install (true == to-be-installed, false == to-be-uninstalled)
01165     */
01166     bool operator()( const CapAndItem & cai )
01167     {
01168         /* check for supplements, if the item has supplements these also must match  */
01169 
01170         PoolItem_Ref item( cai.item );
01171 //      MIL << "TransactLanguage " << item << ", install " << _install << endl;
01172         CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
01173         if (!supplements.empty()) {
01174 //          MIL << "has supplements" << endl;
01175             bool valid = false;
01176             for (CapSet::const_iterator it = supplements.begin(); it != supplements.end(); ++it) {
01177 //              MIL << "Checking " << *it << endl;
01178                 TransactSupplements callback( it->refers() );
01179                 invokeOnEach( _resolver.pool().byNameBegin( it->index() ),
01180                               _resolver.pool().byNameEnd( it->index() ),
01181                               functor::functorRef<bool,PoolItem>( callback ) );
01182                 if (callback.valid) {
01183                     valid = true;               // found a supplements match
01184                     break;
01185                 }
01186             }
01187             if (!valid) {
01188 //              MIL << "All supplements false" << endl;
01189                 return true;                    // no supplements matched, we're done
01190             }
01191         }
01192 
01193         PoolItem_Ref dummy;
01194         if (_install) {
01195             if (item.status().staysUninstalled()) {
01196                 transactItems( PoolItem_Ref(), item, _install, true, dummy );
01197             }
01198         }
01199         else {
01200             if (item.status().staysInstalled()) {
01201                 transactItems( item, PoolItem_Ref(), _install, true, dummy );
01202             }
01203         }
01204         return true;
01205     }
01206 };
01207 
01208 
01209 
01210 //
01211 // transact a single object
01212 // -> do a 'single step' resolving either installing or removing
01213 //    required and recommended PoolItems
01214 
01215 bool
01216 Resolver::transactResObject( ResObject::constPtr robj, bool install)
01217 {
01218     if (robj == NULL) {
01219         ERR << "NULL ResObject" << endl;
01220     }
01221     _XDEBUG( "transactResObject(" << *robj << ", " << (install?"install":"remove") << ")" );
01222 
01223     if (robj->kind() == ResTraits<Language>::kind) {
01224         TransactLanguage callback( *this, robj, install );
01225         Dep dep( Dep::FRESHENS );
01226         invokeOnEach( pool().byCapabilityIndexBegin( robj->name(), dep ),
01227                       pool().byCapabilityIndexEnd( robj->name(), dep ),
01228                       functor::functorRef<bool,CapAndItem>( callback ) );
01229 
01230     }
01231     std::list<PoolItem_Ref> added;
01232 
01233     // loop over 'recommends' and 'requires' of this item and collect additional
01234     //  items of the same kind on the way
01235 
01236     transactCaps( _pool, robj->dep( Dep::RECOMMENDS ), install, true, added );
01237     transactCaps( _pool, robj->dep( Dep::REQUIRES ), install, false, added );
01238 
01239     // if any additional items were collected, call this functions again recursively
01240     //   This is guaranteed to finish since additional items are those which were not selected before
01241     //   and this function is only called for already selected items. So added really only contains
01242     //   'new' items.
01243 
01244     for (std::list<PoolItem_Ref>::const_iterator it = added.begin(); it != added.end(); ++it) {
01245         if ((*it)->kind() == robj->kind()) {
01246             transactResObject( it->resolvable(), install );
01247         }
01248     }
01249 
01250     // not used anyway
01251     return true;
01252 }
01253 
01254 //
01255 // helper to transact all objects of a specific kind
01256 //  see Resolver::transactResKind
01257 // item is to-be-installed (install == true) or to-be-uninstalled
01258 // -> run transactResObject() accordingly
01259 
01260 struct TransactKind : public resfilter::PoolItemFilterFunctor
01261 {
01262     Resolver & _resolver;
01263     bool install;               // true if to-be-installed, else to-be-uninstalled
01264     bool result;
01265 
01266     TransactKind( Resolver & r )
01267         : _resolver( r )
01268         , result( true )
01269     { }
01270 
01271     bool operator()( PoolItem_Ref item )
01272     {
01273         result = _resolver.transactResObject( item.resolvable(), install );
01274         return true;
01275     }
01276 };
01277 
01278 
01279 bool
01280 Resolver::transactResKind( Resolvable::Kind kind )
01281 {
01282     TransactKind callback (*this);
01283 
01284     _XDEBUG( "transactResKind(" << kind << ")" );
01285 
01286     // check all uninstalls
01287     callback.install = false;
01288     invokeOnEach( pool().byKindBegin( kind ),
01289                   pool().byKindEnd( kind ),
01290                   functor::chain( resfilter::ByTransact(), resfilter::ByInstalled ()),
01291                   functor::functorRef<bool,PoolItem>( callback ) );
01292 
01293     // check all installs
01294     callback.install = true;
01295     invokeOnEach( pool().byKindBegin( kind ),
01296                   pool().byKindEnd( kind ),
01297                   functor::chain( resfilter::ByTransact(), resfilter::ByUninstalled ()),
01298                   functor::functorRef<bool,PoolItem>( callback ) );
01299 
01300     return callback.result;
01301 }
01302 
01303 
01304 struct TransactReset : public resfilter::PoolItemFilterFunctor
01305 {
01306     ResStatus::TransactByValue _causer;
01307     TransactReset( ResStatus::TransactByValue causer )
01308         : _causer( causer )
01309     { }
01310 
01311     bool operator()( PoolItem_Ref item )                // only transacts() items go here
01312     {
01313         item.status().resetTransact( _causer );
01314         return true;
01315     }
01316 };
01317 
01318 
01319 void
01320 Resolver::transactReset( ResStatus::TransactByValue causer )
01321 {
01322     TransactReset info( causer );
01323     MIL << "transactReset(" << causer << ")" << endl;
01324     invokeOnEach ( _pool.begin(), _pool.end(),
01325                    resfilter::ByTransact( ),
01326                    functor::functorRef<bool,PoolItem>(info) );
01327     return;
01328 }
01329 
01331     };// namespace detail
01334   };// namespace solver
01337 };// namespace zypp
01339 

Generated on Mon Jun 5 19:10:34 2006 for zypp by  doxygen 1.4.6