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::Patch>::kind);
00415         ordered.push_back (ResTraits<zypp::Pattern>::kind);
00416         ordered.push_back (ResTraits<zypp::Product>::kind);
00417     }
00418 
00419     if (context == NULL)
00420         context = new ResolverContext(_pool, _architecture);
00421 
00422     context->setEstablishing (true);
00423     context->setIgnoreCababilities (_ignoreConflicts,
00424                                     _ignoreRequires,
00425                                     _ignoreObsoletes,
00426                                     _ignoreInstalledItem,
00427                                     _ignoreArchitectureItem);
00428     context->setForceResolve( _forceResolve );
00429     context->setUpgradeMode( _upgradeMode );
00430 
00431     for (KindList::const_iterator iter = ordered.begin(); iter != ordered.end(); iter++) {
00432         const Resolvable::Kind kind = *iter;
00433 
00434         DBG << "establishing state for kind " << kind.asString() << endl;
00435 
00436         //world()->foreachResItemByKind (kind, trial_establish_cb, this);
00437 
00438         EstablishState info (*this);
00439 
00440         invokeOnEach( pool().byKindBegin( kind ),
00441                       pool().byKindEnd( kind ),
00442                       functor::functorRef<bool,PoolItem>(info) );
00443 
00444         // process the queue
00445         resolveDependencies( context );
00446 
00447         reset();
00448     }
00449 
00450     context->setEstablishing (false);
00451 
00452     _best_context = context;
00453 
00454     return;
00455 }
00456 
00457 
00458 bool
00459 Resolver::establishPool ()
00460 {
00461     MIL << "Resolver::establishPool()" << endl;
00462 
00463     establishState ();                                          // establish !
00464     ResolverContext_Ptr solution = bestContext();
00465 
00466     if (solution) {                                             // copy solution back to pool
00467         solution->foreachMarked (solution_to_pool, (void *)1);  // as APPL_LOW
00468     }
00469     else {
00470         ERR << "establishState did not return a bestContext" << endl;
00471         return false;
00472     }
00473 
00474     return true;
00475 }
00476 
00477 
00478 //---------------------------------------------------------------------------
00479 // freshen state
00480 
00481 typedef map<string, PoolItem_Ref> FreshenMap;
00482 
00483 // add item to itemmap
00484 //  check for item with same name and only keep
00485 //  best architecture, best version
00486 
00487 static void
00488 addToFreshen( PoolItem_Ref item, FreshenMap & itemmap )
00489 {
00490     FreshenMap::iterator it = itemmap.find( item->name() );
00491     if (it != itemmap.end()) {                                  // item with same name found
00492         int cmp = it->second->arch().compare( item->arch() );
00493         if (cmp < 0) {                                          // new item has better arch
00494             it->second = item;
00495         }
00496         else if (cmp == 0) {                                    // new item has equal arch
00497             if (it->second->edition().compare( item->edition() ) < 0) {
00498                 it->second = item;                              // new item has better edition
00499             }
00500         }
00501     }
00502     else {
00503         itemmap[item->name()] = item;
00504     }
00505     return;
00506 }
00507 
00508 
00509 struct FreshenState
00510 {
00511     FreshenMap itemmap;
00512 
00513     FreshenState()
00514     { }
00515 
00516     bool operator()( PoolItem_Ref item)
00517     {
00518         CapSet freshens( item->dep( Dep::FRESHENS ) );
00519         if (!freshens.empty()) {
00520             addToFreshen( item, itemmap );
00521         }
00522         else {                                  // if no freshens, look at supplements
00523             // Also regarding supplements e.g. in order to recognize
00524             // modalias dependencies. Bug #163140
00525             CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
00526             if (!supplements.empty()) {
00527                 addToFreshen( item, itemmap );
00528             }
00529         }
00530         return true;
00531     }
00532 };
00533 
00534 
00535 void
00536 Resolver::freshenState( ResolverContext_Ptr context )
00537 {
00538     _DEBUG( "Resolver::freshenState ()" );
00539 
00540     if (context == NULL)
00541         context = new ResolverContext( _pool, _architecture );
00542 
00543     context->setEstablishing( true );
00544     context->setIgnoreCababilities( _ignoreConflicts,
00545                                     _ignoreRequires,
00546                                     _ignoreObsoletes,
00547                                     _ignoreInstalledItem,
00548                                     _ignoreArchitectureItem );
00549     context->setForceResolve( _forceResolve );
00550     context->setUpgradeMode( _upgradeMode );
00551 
00552     FreshenState info;
00553 
00554     // collect items to be established
00555 
00556     invokeOnEach( pool().byKindBegin( ResTraits<zypp::Package>::kind ),
00557                       pool().byKindEnd( ResTraits<zypp::Package>::kind ),
00558                       functor::functorRef<bool,PoolItem>(info) );
00559 
00560     // schedule all collected items for establish
00561 
00562     for (FreshenMap::iterator it = info.itemmap.begin(); it != info.itemmap.end(); ++it) {
00563         addPoolItemToEstablish( it->second );
00564     }
00565 
00566     // process the queue
00567     resolveDependencies( context );
00568 
00569     reset();
00570 
00571     context->setEstablishing( false );
00572 
00573     _best_context = context;
00574 
00575     return;
00576 }
00577 
00578 
00579 bool
00580 Resolver::freshenPool ()
00581 {
00582     MIL << "Resolver::freshenPool()" << endl;
00583 
00584     freshenState ();                                            // establish all packages with freshens !
00585     ResolverContext_Ptr solution = bestContext();
00586 
00587     if (solution) {                                             // copy solution back to pool
00588         solution->foreachMarked (solution_to_pool, (void *)1);  // as APPL_LOW
00589     }
00590     else {
00591         ERR << "freshenState did not return a bestContext" << endl;
00592         return false;
00593     }
00594 
00595     return true;
00596 }
00597 
00598 //---------------------------------------------------------------------------
00599 
00600 bool
00601 Resolver::resolveDependencies (const ResolverContext_Ptr context)
00602 {
00603 
00604     time_t t_start, t_now;
00605 
00606     MIL << "Resolver::resolveDependencies()" << endl;
00607 
00608     _pending_queues.clear();
00609     _pruned_queues.clear();
00610     _complete_queues.clear();
00611     _deferred_queues.clear();
00612     _invalid_queues.clear();
00613     _valid_solution_count = 0;
00614     _best_context = NULL;
00615 
00616 #warning local items disabled
00617 #if 0
00618     bool have_local_items = false;
00619 
00620     /* Walk through are list of to-be-installed packages and see if any of them are local. */
00621 
00622     for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00623         if ((*iter)->local()) {
00624             have_local_items = true;
00625             break;
00626         }
00627     }
00628 
00629     World_Ptr the_world = world();
00630     StoreWorld_Ptr local_world = NULL;
00631     MultiWorld_Ptr local_multiworld = NULL;
00632 
00633     Channel_Ptr local_channel = NULL;
00634 
00635     if (have_local_items) {
00636         local_multiworld = new MultiWorld();
00637         local_world = new StoreWorld();
00638 
00639         local_channel = new Channel ("", "Local ResItems", "@local", "");
00640 
00641         local_world->addChannel (local_channel);
00642 
00643         local_multiworld->addSubworld (local_world);
00644         local_multiworld->addSubworld (the_world);
00645 
00646         the_world = local_multiworld;
00647     }
00648 #endif
00649 
00650     // create initial_queue
00651 
00652     ResolverQueue_Ptr initial_queue = new ResolverQueue(_pool, _architecture, context);
00653 
00654     // Initialize all ignoring dependencies
00655     initial_queue->context()->setIgnoreCababilities (_ignoreConflicts,
00656                                     _ignoreRequires,
00657                                     _ignoreObsoletes,
00658                                     _ignoreInstalledItem,
00659                                     _ignoreArchitectureItem);
00660     initial_queue->context()->setForceResolve( _forceResolve );
00661     initial_queue->context()->setUpgradeMode( _upgradeMode );
00662 
00663     /* If this is a verify, we do a "soft resolution" */
00664 
00665     initial_queue->context()->setVerifying( _verifying );
00666 
00667     /* Add extra items. */
00668 
00669     for (QueueItemList::const_iterator iter = _initial_items.begin(); iter != _initial_items.end(); iter++) {
00670         initial_queue->addItem (*iter);
00671     }
00672 
00673     for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00674         PoolItem_Ref r = *iter;
00675 
00676 #warning local items disabled
00677 #if 0
00678         /* Add local packages to our dummy channel. */
00679         if (r->local()) {
00680             assert (local_channel != NULL);
00681             ResItem_Ptr r1 = const_pointer_cast<ResItem>(r);
00682             r1->setChannel (local_channel);
00683             local_world->addPoolItem_Ref (r);
00684         }
00685 #endif
00686         initial_queue->addPoolItemToInstall (r);
00687     }
00688 
00689     for (PoolItemList::const_iterator iter = _items_to_remove.begin(); iter != _items_to_remove.end(); iter++) {
00690         if (!_upgradeMode)
00691             initial_queue->addPoolItemToRemove (*iter, true /* remove-only mode */);
00692         else
00693             //   Checking old dependencies for packages which will be updated.
00694             //   E.g. foo provides a dependecy which foo-new does not provides anymore.
00695             //   So check, if there is a packages installed which requires foo.
00696             //   Testcase exercise-bug150844-test.xml
00697             //   Testcase Bug156439-test.xml
00698             initial_queue->addPoolItemToRemove (*iter, false /* no remove-only mode */);
00699     }
00700 
00701     for (PoolItemList::const_iterator iter = _items_to_verify.begin(); iter != _items_to_verify.end(); iter++) {
00702         initial_queue->addPoolItemToVerify (*iter);
00703     }
00704 
00705     for (PoolItemList::const_iterator iter = _items_to_establish.begin(); iter != _items_to_establish.end(); iter++) {
00706         initial_queue->addPoolItemToEstablish (*iter);
00707     }
00708 
00709     for (CapSet::const_iterator iter = _extra_caps.begin(); iter != _extra_caps.end(); iter++) {
00710         initial_queue->addExtraCapability (*iter);
00711     }
00712 
00713     for (CapSet::const_iterator iter = _extra_conflicts.begin(); iter != _extra_conflicts.end(); iter++) {
00714         initial_queue->addExtraConflict (*iter);
00715     }
00716 
00717     // Adding System resolvable
00718     assertSystemResObjectInPool();
00719 
00720     _DEBUG( "Initial Queue: [" << *initial_queue << "]" );
00721 
00722     if (initial_queue->isEmpty()) {
00723         INT << "Empty Queue, nothing to resolve" << endl;
00724 
00725         return true;
00726     }
00727 
00728     _best_context = NULL;
00729 
00730     _pending_queues.push_front (initial_queue);
00731 
00732     time (&t_start);
00733 
00734     while (!_pending_queues.empty()) {
00735 
00736         _DEBUG( "Pend " << (long) _pending_queues.size()
00737                               << " / Cmpl " << (long) _complete_queues.size()
00738                               << " / Prun " << (long) _pruned_queues.size()
00739                               << " / Defr " << (long) _deferred_queues.size()
00740                               << " / Invl " << (long) _invalid_queues.size() );
00741 
00742               if (_timeout_seconds > 0) {
00743                     time (&t_now);
00744                     if (difftime (t_now, t_start) > _timeout_seconds) {
00745                         _timed_out = true;
00746                     break;
00747                 }
00748             }
00749 
00750             ResolverQueue_Ptr queue = _pending_queues.front();
00751             _pending_queues.pop_front();
00752             ResolverContext_Ptr context = queue->context();
00753 
00754             queue->process();
00755 
00756         if (queue->isInvalid ()) {
00757 
00758             DBG << "Invalid Queue\n" << endl;;
00759             _invalid_queues.push_back(queue);
00760 
00761         } else if (queue->isEmpty ()) {
00762 
00763             DBG <<"Empty Queue\n" << endl;
00764 
00765             _complete_queues.push_back(queue);
00766 
00767             ++_valid_solution_count;
00768 
00769             /* Compare this solution to our previous favorite.  In the case of a tie,
00770                the first solution wins --- yeah, I know this is lame, but it shouldn't
00771                be an issue too much of the time. */
00772 
00773             if (_best_context == NULL
00774                 || _best_context->compare (context) < 0) {
00775                 _best_context = context;
00776             }
00777 
00778         } else if (_best_context != NULL
00779                    && _best_context->partialCompare (context) > 0) {
00780 
00781             /* If we aren't currently as good as our previous best complete solution,
00782                this solution gets pruned. */
00783 
00784             DBG << "PRUNED!" << endl;
00785 
00786             _pruned_queues.push_back(queue);
00787 
00788         } else {
00789 
00790             /* If our queue is isn't empty and isn't invalid, that can only mean
00791                one thing: we are down to nothing but branches. */
00792 
00793             queue->splitFirstBranch (_pending_queues, _deferred_queues);
00794         }
00795 
00796         /* If we have run out of pending queues w/o finding any solutions,
00797            and if we have deferred queues, make the first deferred queue
00798            pending. */
00799 
00800         if (_pending_queues.empty()
00801             && _complete_queues.empty()
00802             && !_deferred_queues.empty()) {
00803             _pending_queues.push_back(_deferred_queues.front());
00804         }
00805     }
00806     _DEBUG("Pend " << (long) _pending_queues.size()
00807                    << " / Cmpl " << (long) _complete_queues.size()
00808                    << " / Prun " << (long) _pruned_queues.size()
00809                    << " / Defr " << (long) _deferred_queues.size()
00810                    << " / Invl " << (long) _invalid_queues.size() );
00811 
00812     return _best_context && _best_context->isValid();
00813 }
00814 
00815 
00816 //----------------------------------------------------------------------------
00817 // undo
00818 
00819 struct UndoTransact : public resfilter::PoolItemFilterFunctor
00820 {
00821     UndoTransact ()
00822     { }
00823 
00824     bool operator()( PoolItem_Ref item )                // only transacts() items go here
00825     {
00826         item.status().resetTransact( ResStatus::APPL_LOW );// clear any solver/establish transactions
00827         return true;
00828     }
00829 };
00830 
00831 void
00832 Resolver::undo(void)
00833 {
00834     UndoTransact info;
00835     MIL << "*** undo ***" << endl;
00836     invokeOnEach ( _pool.begin(), _pool.end(),
00837                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
00838                    functor::functorRef<bool,PoolItem>(info) );
00839     // These conflict should be ignored of the concering item
00840     _ignoreConflicts.clear();
00841     // These requires should be ignored of the concering item
00842     _ignoreRequires.clear();
00843     // These obsoletes should be ignored of the concering item
00844     _ignoreObsoletes.clear();
00845     // Ignore architecture of the item
00846     _ignoreArchitecture.clear();
00847     // Ignore the status "installed" of the item
00848     _ignoreInstalledItem.clear();
00849     // Ignore the architecture of the item
00850     _ignoreArchitectureItem.clear();
00851 
00852 
00853     return;
00854 }
00855 
00856 //----------------------------------------------------------------------------
00857 // resolvePool
00858 
00859 struct CollectTransact : public resfilter::PoolItemFilterFunctor
00860 {
00861     Resolver & resolver;
00862 
00863     CollectTransact (Resolver & r)
00864         : resolver (r)
00865     { }
00866 
00867     bool operator()( PoolItem_Ref item )                // only transacts() items go here
00868     {
00869         ResStatus status = item.status();
00870         _XDEBUG( "CollectTransact(" << item << ")" );
00871         bool by_solver = (status.isBySolver() || status.isByApplLow());
00872 
00873         if (by_solver) {
00874             item.status().resetTransact( ResStatus::APPL_LOW );// clear any solver/establish transactions
00875             return true;                                // back out here, dont re-queue former solver result
00876         }
00877 
00878         if (status.isToBeInstalled()) {
00879             resolver.addPoolItemToInstall(item);        // -> install!
00880         }
00881         if (status.isToBeUninstalled()) {
00882             resolver.addPoolItemToRemove(item);         // -> remove !
00883         }
00884         if (status.isIncomplete()) {                    // incomplete (re-install needed)
00885             PoolItem_Ref reinstall = Helper::findReinstallItem (resolver.pool(), item);
00886             if (reinstall) {
00887                 MIL << "Reinstall " << reinstall << " for incomplete " << item << endl;
00888                 resolver.addPoolItemToInstall(reinstall);       // -> install!
00889             }
00890             else {
00891                 WAR << "Can't find " << item << " for re-installation" << endl;
00892             }
00893         }
00894         return true;
00895     }
00896 };
00897 
00898 
00899 static void
00900 show_pool( ResPool pool )
00901 {
00902     int count = 1;
00903     static bool full_pool_shown = false;
00904 
00905     MIL << "---------------------------------------" << endl;
00906     for (ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it, ++count) {
00907 
00908         if (!full_pool_shown                                    // show item if not shown all before
00909             || it->status().transacts()                         // or transacts
00910             || !it->status().isUndetermined())                  // or established status
00911         {
00912             MIL << count << ": " << *it << endl;
00913         }
00914 
00915     }
00916     MIL << "---------------------------------------" << endl;
00917     full_pool_shown = true;
00918 }
00919 
00920 //  This function loops over the pool and grabs
00921 //  all item.status().transacts() and item.status().byUser()
00922 //  It clears all previous bySolver() states also
00923 //
00924 //  Every toBeInstalled is passed to zypp::solver:detail::Resolver.addPoolItemToInstall()
00925 //  Every toBeUninstalled is passed to zypp::solver:detail::Resolver.addPoolItemToRemove()
00926 //
00927 //  Then zypp::solver:detail::Resolver.resolveDependencies() is called.
00928 //
00929 //  zypp::solver:detail::Resolver then returns a ResolverContext via bestContext() which
00930 //  describes the best solution. If bestContext() is NULL, no solution was found.
00931 //
00932 //  ResolverContext has a foreachMarked() iterator function which loops over all
00933 //  items of the solutions. These must be written back to the pool.
00934 
00935 
00936 bool
00937 Resolver::resolvePool ()
00938 {
00939 
00940     CollectTransact info (*this);
00941 
00942     // cleanup before next run
00943     reset();
00944 
00945 #if 1
00946 
00947     MIL << "Resolver::resolvePool()" << endl;
00948     MIL << "Pool before resolve" << endl;
00949     show_pool( _pool );
00950 
00951 #endif
00952     invokeOnEach ( _pool.begin(), _pool.end(),
00953                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
00954                    functor::functorRef<bool,PoolItem>(info) );
00955 
00956     bool have_solution = resolveDependencies ();                // resolve !
00957 
00958     if (have_solution) {                                        // copy solution back to pool
00959         MIL << "Have solution, copying back to pool" << endl;
00960         ResolverContext_Ptr solution = bestContext();
00961         solution->foreachMarked (solution_to_pool, NULL);
00962 #if 1
00963         MIL << "Pool after resolve" << endl;
00964         show_pool( _pool );
00965 #endif
00966     }
00967     else {
00968         MIL << "!!! Have NO solution !!!" << endl;
00969     }
00970     return have_solution;
00971 }
00972 
00973 //-----------------------------------------------------------------------------
00974 
00975 static bool
00976 transactItems( PoolItem_Ref installed, PoolItem_Ref uninstalled, bool install, bool soft )
00977 {
00978         if (install) {
00979             if (uninstalled
00980                 && !uninstalled.status().isLocked())
00981             {
00982                 if (soft)
00983                     uninstalled.status().setSoftTransact( true, ResStatus::APPL_LOW );
00984                 else
00985                     uninstalled.status().setTransact( true, ResStatus::APPL_LOW );
00986             }
00987             if (installed
00988                 && !installed.status().isLocked())
00989             {
00990                 installed.status().resetTransact( ResStatus::APPL_LOW );
00991             }
00992         } else {
00993             // uninstall
00994             if (uninstalled
00995                 && !uninstalled.status().isLocked())
00996             {
00997                 uninstalled.status().resetTransact( ResStatus::APPL_LOW );
00998             }
00999             if (installed
01000                 && !installed.status().isLocked())
01001             {
01002                 if (soft)
01003                     installed.status().setSoftTransact( true, ResStatus::APPL_LOW );
01004                 else
01005                     installed.status().setTransact( true, ResStatus::APPL_LOW );
01006             }
01007         }
01008         if (!uninstalled
01009             && !installed)
01010         {
01011             return false;
01012         }
01013     return true;
01014 }
01015 
01016 
01017 // find best available providers for name
01018 
01019 typedef struct { PoolItem_Ref installed; PoolItem_Ref uninstalled; } IandU;
01020 typedef map<string, IandU> IandUMap;
01021 
01022 struct FindIandU
01023 {
01024     IandUMap iandu;             // install, and best uninstalled
01025 
01026     FindIandU ()
01027     { }
01028 
01029     bool operator()( const CapAndItem & cai )
01030     {
01031         PoolItem item( cai.item );
01032         if ( item.status().staysInstalled() ) {
01033             iandu[item->name()].installed = item;
01034         }
01035         else if ( item.status().staysUninstalled() ) {                  // only look at uninstalled
01036             IandUMap::iterator it = iandu.find( item->name() );
01037 
01038             if (it != iandu.end()
01039                 && it->second.uninstalled)
01040             {                                                           // uninstalled with same name found
01041                 int cmp = it->second.uninstalled->arch().compare( item->arch() );
01042                 if (cmp < 0) {                                          // new item has better arch
01043                     it->second.uninstalled = item;
01044                 }
01045                 else if (cmp == 0) {                                    // new item has equal arch
01046                     if (it->second.uninstalled->edition().compare( item->edition() ) < 0) {
01047                         it->second.uninstalled = item;                  // new item has better edition
01048                     }
01049                 }
01050             }
01051             else {
01052                 iandu[item->name()].uninstalled = item;
01053             }
01054         }
01055         return true;
01056     }
01057 };
01058 
01059 
01060 //
01061 // transact list of capabilities (requires or recommends)
01062 //  return false if one couldn't be matched
01063 //
01064 // see Resolver::transactResObject
01065 //
01066 
01067 static bool
01068 transactCaps( const ResPool & pool, const CapSet & caps, bool install, bool soft )
01069 {
01070     bool result = true;
01071 
01072     // loop over capabilities and find (best) matching provider
01073 
01074     for (CapSet::const_iterator cit = caps.begin(); cit != caps.end(); ++cit) {
01075 
01076         FindIandU callback;
01077         Dep dep( Dep::PROVIDES );
01078         invokeOnEach( pool.byCapabilityIndexBegin( cit->index(), dep ),
01079                       pool.byCapabilityIndexEnd( cit->index(), dep ),
01080                       resfilter::ByCapMatch( *cit ) ,
01081                       functor::functorRef<bool,CapAndItem>(callback) );
01082 
01083         for (IandUMap::const_iterator it = callback.iandu.begin(); it !=  callback.iandu.end(); ++it) {
01084             if (!transactItems( it->second.installed, it->second.uninstalled, install, soft )) {
01085                 result = false;
01086             }
01087         }
01088         
01089     }
01090     return result;
01091 }
01092 
01093 
01094 struct TransactSupplements : public resfilter::PoolItemFilterFunctor
01095 {
01096     const Resolvable::Kind &_kind;
01097     bool valid;
01098 
01099     TransactSupplements( const Resolvable::Kind & kind )
01100         : _kind( kind )
01101         , valid( false )
01102     { }
01103 
01104     bool operator()( PoolItem_Ref item )
01105     {
01106 //      MIL << "TransactSupplements(" << item << ")" << endl;
01107         if (item->kind() == _kind
01108             && (item.status().staysInstalled()
01109                 || item.status().isToBeInstalled()))
01110         {
01111             valid = true;
01112             return false;               // end search here
01113         }
01114         return true;
01115     }
01116 };
01117 
01118 //
01119 // transact due to a language dependency
01120 // -> look through the pool and run transactResObject() accordingly
01121 
01122 struct TransactLanguage : public resfilter::PoolItemFilterFunctor
01123 {
01124     Resolver & _resolver;
01125     ResObject::constPtr _langObj;
01126     bool _install;
01127 
01128     TransactLanguage( Resolver & r, ResObject::constPtr langObj, bool install )
01129         : _resolver( r )
01130         , _langObj( langObj )
01131         , _install( install )
01132     { }
01133 
01134     /* item has a freshens on _langObj
01135         _langObj just transacted to _install (true == to-be-installed, false == to-be-uninstalled)
01136     */
01137     bool operator()( const CapAndItem & cai )
01138     {
01139         /* check for supplements, if the item has supplements these also must match  */
01140 
01141         PoolItem_Ref item( cai.item );
01142 //      MIL << "TransactLanguage " << item << ", install " << _install << endl;
01143         CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
01144         if (!supplements.empty()) {
01145 //          MIL << "has supplements" << endl;
01146             bool valid = false;
01147             for (CapSet::const_iterator it = supplements.begin(); it != supplements.end(); ++it) {
01148 //              MIL << "Checking " << *it << endl;
01149                 TransactSupplements callback( it->refers() );
01150                 invokeOnEach( _resolver.pool().byNameBegin( it->index() ),
01151                               _resolver.pool().byNameEnd( it->index() ),
01152                               functor::functorRef<bool,PoolItem>( callback ) );
01153                 if (callback.valid) {
01154                     valid = true;               // found a supplements match
01155                     break;
01156                 }
01157             }
01158             if (!valid) {
01159 //              MIL << "All supplements false" << endl;
01160                 return true;                    // no supplements matched, we're done
01161             }
01162         }
01163 
01164         if (_install) {
01165             if (item.status().staysUninstalled()) {
01166                 transactItems( PoolItem_Ref(), item, _install, true );
01167             }
01168         }
01169         else {
01170             if (item.status().staysInstalled()) {
01171                 transactItems( item, PoolItem_Ref(), _install, true );
01172             }
01173         }
01174         return true;
01175     }
01176 };
01177 
01178 
01179 
01180 //
01181 // transact a single object
01182 // -> do a 'single step' resolving either installing or removing
01183 //    required and recommended PoolItems
01184 
01185 bool
01186 Resolver::transactResObject( ResObject::constPtr robj, bool install)
01187 {
01188     if (robj == NULL) {
01189         ERR << "NULL ResObject" << endl;
01190     }
01191     DBG << "transactResObject(" << *robj << ", " << (install?"install":"remove") << ")" << endl;
01192 
01193     if (robj->kind() == ResTraits<Language>::kind) {
01194         TransactLanguage callback( *this, robj, install );
01195         Dep dep( Dep::FRESHENS );
01196         invokeOnEach( pool().byCapabilityIndexBegin( robj->name(), dep ),
01197                       pool().byCapabilityIndexEnd( robj->name(), dep ),
01198                       functor::functorRef<bool,CapAndItem>( callback ) );
01199 
01200     }
01201     transactCaps( _pool, robj->dep( Dep::RECOMMENDS ), install, true );
01202     return transactCaps( _pool, robj->dep( Dep::REQUIRES ), install, false );
01203 }
01204 
01205 //
01206 // helper to transact all objects of a specific kind
01207 //  see Resolver::transactResKind
01208 // item is to-be-installed (install == true) or to-be-uninstalled
01209 // -> run transactResObject() accordingly
01210 
01211 struct TransactKind : public resfilter::PoolItemFilterFunctor
01212 {
01213     Resolver & _resolver;
01214     bool install;               // true if to-be-installed, else to-be-uninstalled
01215     bool result;
01216 
01217     TransactKind( Resolver & r )
01218         : _resolver( r )
01219         , result( true )
01220     { }
01221 
01222     bool operator()( PoolItem_Ref item )
01223     {
01224         result = _resolver.transactResObject( item.resolvable(), install );
01225         return true;
01226     }
01227 };
01228 
01229 
01230 bool
01231 Resolver::transactResKind( Resolvable::Kind kind )
01232 {
01233     TransactKind callback (*this);
01234 
01235     DBG << "transactResKind(" << kind << ")" << endl;
01236 
01237     // check all uninstalls
01238     callback.install = false;
01239     invokeOnEach( pool().byKindBegin( kind ),
01240                   pool().byKindEnd( kind ),
01241                   functor::chain( resfilter::ByTransact(), resfilter::ByInstalled ()),
01242                   functor::functorRef<bool,PoolItem>( callback ) );
01243 
01244     // check all installs
01245     callback.install = true;
01246     invokeOnEach( pool().byKindBegin( kind ),
01247                   pool().byKindEnd( kind ),
01248                   functor::chain( resfilter::ByTransact(), resfilter::ByUninstalled ()),
01249                   functor::functorRef<bool,PoolItem>( callback ) );
01250 
01251     return callback.result;
01252 }
01253 
01254 
01255 struct TransactReset : public resfilter::PoolItemFilterFunctor
01256 {
01257     ResStatus::TransactByValue _causer;
01258     TransactReset( ResStatus::TransactByValue causer )
01259         : _causer( causer )
01260     { }
01261 
01262     bool operator()( PoolItem_Ref item )                // only transacts() items go here
01263     {
01264         item.status().resetTransact( _causer );
01265         return true;
01266     }
01267 };
01268 
01269 
01270 void
01271 Resolver::transactReset( ResStatus::TransactByValue causer )
01272 {
01273     TransactReset info( causer );
01274     MIL << "transactReset(" << causer << ")" << endl;
01275     invokeOnEach ( _pool.begin(), _pool.end(),
01276                    resfilter::ByTransact( ),
01277                    functor::functorRef<bool,PoolItem>(info) );
01278     return;
01279 }
01280 
01282     };// namespace detail
01285   };// namespace solver
01288 };// namespace zypp
01290 

Generated on Thu May 4 16:03:24 2006 for zypp by  doxygen 1.4.6