ResolverQueue.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /* ResolverQueue.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 <map>
00023 
00024 #include "zypp/base/String.h"
00025 #include "zypp/solver/detail/ResolverQueue.h"
00026 #include "zypp/solver/detail/QueueItemBranch.h"
00027 #include "zypp/solver/detail/QueueItemConflict.h"
00028 #include "zypp/solver/detail/QueueItemEstablish.h"
00029 #include "zypp/solver/detail/QueueItemGroup.h"
00030 #include "zypp/solver/detail/QueueItemInstall.h"
00031 #include "zypp/solver/detail/QueueItemRequire.h"
00032 #include "zypp/solver/detail/QueueItemUninstall.h"
00033 #include "zypp/solver/detail/ResolverContext.h"
00034 #include "zypp/CapSet.h"
00035 #include "zypp/base/Logger.h"
00036 
00038 namespace zypp
00039 { 
00040 
00041   namespace solver
00042   { 
00043 
00044     namespace detail
00045     { 
00046 
00047 using namespace std;
00048 
00049 IMPL_PTR_TYPE(ResolverQueue);
00050 
00051 //---------------------------------------------------------------------------
00052 
00053 
00054 //---------------------------------------------------------------------------
00055 
00056 ostream&
00057 operator<<( ostream& os, const ResolverQueue & resolverqueue)
00058 {
00059     os << str::form ("Context [%p]", (const void *)resolverqueue._context.get());
00060     os <<  ", " << resolverqueue._qitems.size() << " Items:" << endl << "\t";
00061     os << resolverqueue._qitems;
00062     return os;
00063 }
00064 
00065 //---------------------------------------------------------------------------
00066 
00067 ResolverQueue::ResolverQueue (const ResPool & pool, const Arch & arch, ResolverContext_Ptr context)
00068     : _context (context)
00069 {
00070     _XDEBUG("ResolverQueue::ResolverQueue(pool,... )");
00071     if (context == NULL)
00072         _context = new ResolverContext(pool, arch);
00073 }
00074 
00075 
00076 ResolverQueue::~ResolverQueue()
00077 {
00078 }
00079 
00080 //---------------------------------------------------------------------------
00081 
00082 void
00083 ResolverQueue::addPoolItemToInstall (PoolItem_Ref poolItem)
00084 {
00085     QueueItemInstall_Ptr qitem;
00086 
00087     if (_context->isPresent (poolItem)
00088         && poolItem.status().staysInstalled()) {
00089         WAR << poolItem << " is already installed" << endl;
00090         return;
00091     }
00092 
00093     qitem = new QueueItemInstall (_context->pool(), poolItem, poolItem.status().isSoftInstall());
00094     poolItem.status().setSoftInstall(false);
00095     qitem->setExplicitlyRequested ();
00096 
00097     addItem (qitem);
00098 }
00099 
00100 
00101 void
00102 ResolverQueue::addPoolItemToEstablish (PoolItem_Ref poolItem)
00103 {
00104     QueueItemEstablish_Ptr qitem;
00105 
00106     qitem = new QueueItemEstablish (_context->pool(), poolItem);
00107     qitem->setExplicitlyRequested ();
00108 
00109     addItem (qitem);
00110 }
00111 
00112 
00113 void
00114 ResolverQueue::addPoolItemToRemove (PoolItem_Ref poolItem, bool remove_only_mode)
00115 {
00116     QueueItemUninstall_Ptr qitem;
00117 
00118     if (_context->isAbsent (poolItem))
00119         return;
00120 
00121     qitem = new QueueItemUninstall (_context->pool(), poolItem, QueueItemUninstall::EXPLICIT, poolItem.status().isSoftUninstall());
00122     poolItem.status().setSoftUninstall(false);
00123     if (remove_only_mode)
00124         qitem->setRemoveOnly ();
00125 
00126     qitem->setExplicitlyRequested ();
00127 
00128     addItem (qitem);
00129 }
00130 
00131 
00132 void
00133 ResolverQueue::addPoolItemToVerify (PoolItem_Ref poolItem)
00134 {
00135     if (poolItem.status().staysInstalled()
00136         || poolItem.status().isToBeInstalled()) {
00137         // regarding only items which will on the system after commit
00138         CapSet requires = poolItem->dep (Dep::REQUIRES);
00139         for (CapSet::const_iterator iter = requires.begin(); iter != requires.end(); ++iter) {
00140             QueueItemRequire_Ptr qitem = new QueueItemRequire (_context->pool(), *iter);
00141             qitem->addPoolItem (poolItem);
00142             addItem (qitem);
00143         }
00144 
00145         CapSet conflicts = poolItem->dep (Dep::CONFLICTS);
00146         for (CapSet::const_iterator iter = conflicts.begin(); iter != conflicts.end(); ++iter) {
00147             QueueItemConflict_Ptr qitem = new QueueItemConflict (_context->pool(), *iter, poolItem);
00148             addItem (qitem);
00149         }
00150     }
00151 }
00152 
00153 
00154 void
00155 ResolverQueue::addExtraCapability (const Capability & dep)
00156 {
00157     QueueItemRequire_Ptr qitem = new QueueItemRequire (_context->pool(), dep);
00158     addItem (qitem);
00159 }
00160 
00161 
00162 void
00163 ResolverQueue::addExtraConflict (const Capability & dep)
00164 {
00165     QueueItemConflict_Ptr qitem = new QueueItemConflict (_context->pool(), dep, PoolItem_Ref());
00166     qitem->setExplicitlyRequested();
00167     addItem (qitem);
00168 }
00169 
00170 
00171 void
00172 ResolverQueue::addItem (QueueItem_Ptr qitem)
00173 {
00174     _qitems.push_back(qitem);
00175 }
00176 
00177 
00178 bool
00179 ResolverQueue::isInvalid ()
00180 {
00181     return _context->isInvalid() || _context->askUser();
00182 }
00183 
00184 
00185 bool
00186 ResolverQueue::containsOnlyBranches ()
00187 {
00188     for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end(); ++iter) {
00189         if (!(*iter)->isBranch())
00190             return false;
00191     }
00192 
00193     return true;
00194 }
00195 
00196 //---------------------------------------------------------------------------
00197 
00198 static int
00199 qitemlist_max_priority (const QueueItemList & qil)
00200 {
00201     int max_priority = -1;
00202     for (QueueItemList::const_iterator iter = qil.begin(); iter != qil.end(); ++iter) {
00203         if ((*iter)->priority() > max_priority) {
00204             max_priority = (*iter)->priority();
00205         }
00206     }
00207 
00208     return max_priority;
00209 }
00210 
00211 
00212 
00213 bool
00214 ResolverQueue::processOnce ()
00215 {
00216     QueueItemList new_qitems;
00217     int max_priority;
00218     bool did_something = false;
00219 
00220     _XDEBUG("ResolverQueue::processOnce()" << (int) _qitems.size() << " items");
00221     while ( (max_priority = qitemlist_max_priority (_qitems)) >= 0
00222             && _context->isValid () ) {
00223 
00224         bool did_something_recently = false;
00225 
00226         for (QueueItemList::iterator iter = _qitems.begin(); iter != _qitems.end() && _context->isValid();) {
00227             QueueItem_Ptr qitem = *iter;
00228             _XDEBUG( "=====> 1st pass: [" << *qitem << "]");
00229             QueueItemList::iterator next = iter; ++next;
00230             if (qitem && qitem->priority() == max_priority) {
00231                 if (qitem->process (_qitems, _context, new_qitems)) {
00232                     did_something_recently = true;
00233                 }
00234                 _qitems.erase (iter);
00235             }
00236             iter = next;
00237         }
00238 
00239         if (did_something_recently) {
00240             did_something = true;
00241         }
00242     }
00243 
00244     _qitems = new_qitems;
00245     _XDEBUG(_qitems.size() << " qitems after first pass");
00246 
00247     /*
00248        Now make a second pass over the queue, removing any super-branches.
00249        (If one branch contains all of the possible items of another branch,
00250        the larger branch can be dropped.
00251     */
00252 
00253     for (QueueItemList::iterator iter = _qitems.begin(); iter != _qitems.end();) {
00254         QueueItemList::iterator next = iter; ++next;
00255         QueueItem_Ptr qitem = *iter;
00256 
00257         _XDEBUG( "=====> 2nd pass: [" << *qitem << "]");
00258         if (qitem->isBranch()) {
00259             _XDEBUG("ResolverQueue::processOnce() is branch");
00260             QueueItemBranch_Ptr branch = dynamic_pointer_cast<QueueItemBranch>(qitem);
00261             for (QueueItemList::const_iterator iter2 = _qitems.begin(); iter2 != _qitems.end(); ++iter2) {
00262                 _XDEBUG("Compare branch with [" << *(*iter2) << "]");
00263                 if (iter != iter2
00264                     && branch->contains (*iter2)) {
00265                     _XDEBUG("Contained within, removing");
00266                     _qitems.erase (iter);
00267                     break;
00268                 }
00269             }
00270         }
00271         iter = next;
00272     }
00273     if (did_something) {
00274       _XDEBUG( "did something: " << _qitems.size() << " qitems");
00275     }
00276     else {
00277       _XDEBUG( "did nothing: " << _qitems.size() << " qitems"); 
00278     }
00279 
00280     return did_something;
00281 }
00282 
00283 
00284 void
00285 ResolverQueue::process ()
00286 {
00287     _XDEBUG("----- Processing -----");
00288     spew ();
00289 
00290     while (_context->isValid ()
00291                  && ! isEmpty ()
00292                  && processOnce ()) {
00293               /* all of the work is in the conditional! */
00294               spew ();
00295     }
00296 }
00297 
00298 
00299 //---------------------------------------------------------------------------
00300 
00301 ResolverQueue_Ptr
00302 ResolverQueue::copy_queue_except_for_branch (QueueItem_Ptr branch_qitem, QueueItem_Ptr subqitem) const
00303 {
00304     ResolverContext_Ptr new_context;
00305     ResolverQueue_Ptr new_queue;
00306     _XDEBUG("copy_queue_except_for_branch");
00307     new_context = new ResolverContext (_context->pool(), _context->architecture(), _context);
00308       
00309     new_queue = new ResolverQueue (new_context->pool(), new_context->architecture(), new_context);
00310 
00311     QueueItemList qil = _qitems;
00312     for (QueueItemList::const_iterator iter = qil.begin(); iter != qil.end(); ++iter) {
00313         QueueItem_Ptr qitem = *iter;
00314         QueueItem_Ptr new_qitem;
00315 
00316         if (qitem == branch_qitem) {
00317             new_qitem = subqitem->copy ();
00318 
00319             if (new_qitem->isInstall()) {
00320                 QueueItemInstall_Ptr install_qitem = dynamic_pointer_cast<QueueItemInstall>(new_qitem);
00321 
00322                 /* Penalties are negative priorities */
00323 #warning FIX priorities                
00324                 int penalty = 0;
00325                 Repository repo = install_qitem->item()->repository();
00326                 //penalty = - src.priority();
00327                 install_qitem->setOtherPenalty (penalty);
00328             }
00329 
00330         } else {
00331 
00332             new_qitem = qitem->copy ();
00333 
00334         }
00335 
00336         new_queue->addItem (new_qitem);
00337     }
00338 
00339     return new_queue;
00340 }
00341 
00342 
00343 void
00344 ResolverQueue::splitFirstBranch (ResolverQueueList & new_queues, ResolverQueueList & deferred_queues)
00345 {
00346     QueueItemBranch_Ptr first_branch = NULL;
00347     typedef std::map <QueueItem_Ptr, QueueItem_Ptr> DeferTable;
00348     DeferTable to_defer;
00349 
00350     for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end() && first_branch == NULL; ++iter) {
00351         QueueItem_Ptr qitem = *iter;
00352         if (qitem->isBranch()) {
00353             first_branch = dynamic_pointer_cast<QueueItemBranch>(qitem);
00354         }
00355     }
00356 
00357     if (first_branch == NULL)
00358         return;
00359 
00360     QueueItemList possible_qitems = first_branch->possibleQItems();
00361 
00362     /*
00363        Check for deferrable qitems: if we have two install qitems where the to-be-installed
00364        poolItems have the same name, then we will defer the lower-priority install if
00365        one of the following is true:
00366        (1) Both poolItems have the same version
00367        (2) The lower-priority channel is a previous version.
00368     */
00369 
00370     for (QueueItemList::const_iterator iter = possible_qitems.begin(); iter != possible_qitems.end(); ++iter) {
00371         QueueItemList::const_iterator iter2 = iter;
00372         for (iter2++; iter2 != possible_qitems.end(); iter2++) {
00373             QueueItem_Ptr qitem = *iter;
00374             QueueItem_Ptr qitem2 = *iter2;
00375 
00376             if (qitem->isInstall() && qitem2->isInstall()) {
00377                 PoolItem_Ref r = (dynamic_pointer_cast<QueueItemInstall>(qitem))->item();
00378                 PoolItem_Ref r2 = (dynamic_pointer_cast<QueueItemInstall>(qitem2))->item();
00379                 Repository repo1 = r->repository();
00380                 Repository repo2 = r2->repository();
00381                 int priority, priority2;
00382 
00383                 priority = _context->getRepoPriority( repo1 );
00384                 priority2 = _context->getRepoPriority( repo2 );
00385 
00386                 if (priority != priority2 && r->name() == r2->name()) {
00387                     if (r->edition().compare(r2->edition()) == 0
00388                         || (priority < priority2 && r->edition().compare(r2->edition()) < 0)
00389                         || (priority > priority2 && r->edition().compare(r2->edition()) > 0))
00390                     {
00391                         if (priority < priority2)
00392                             to_defer[qitem] = qitem;
00393                         else /* if (priority > priority2) */
00394                             to_defer[qitem2] = qitem2;
00395                     }
00396                 }
00397             }
00398         }
00399     }
00400 
00401     for (QueueItemList::const_iterator iter = possible_qitems.begin(); iter != possible_qitems.end(); ++iter) {
00402         ResolverQueue_Ptr new_queue;
00403         QueueItem_Ptr new_qitem = *iter;
00404 
00405         new_queue = copy_queue_except_for_branch ((QueueItem_Ptr) first_branch, new_qitem);
00406 
00407         DeferTable::const_iterator pos = to_defer.find (new_qitem);
00408         if (pos != to_defer.end()) {
00409             deferred_queues.push_back(new_queue);
00410         } else {
00411             new_queues.push_back(new_queue);
00412         }
00413     }
00414 
00415 }
00416 
00417 
00418 void
00419 ResolverQueue::spew ()
00420 {
00421     _XDEBUG( "Resolver Queue: " << (_context->isInvalid() ? "INVALID" : "") );
00422 
00423     if (_qitems.empty()) {
00424 
00425         _XDEBUG( "  (empty)" );
00426 
00427     } else {
00428         for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end(); ++iter) {
00429             _XDEBUG( "  " << *(*iter) );
00430         }
00431 
00432     }
00433 }
00434 
00436     };// namespace detail
00439   };// namespace solver
00442 };// namespace zypp
00444 

Generated on Tue Sep 25 19:23:08 2007 for libzypp by  doxygen 1.5.3